├── .gitignore ├── uefi_apps ├── LiorPkg │ ├── Include │ │ └── .gitkeep │ ├── Lior │ │ ├── lior.inf │ │ └── HelloWorld.c │ ├── lior.dec │ └── lior.dsc └── lior_pkg.cmake ├── LICENSE ├── documentation └── dev_notes.md ├── cmake_files ├── unix │ ├── build_abi.cmake │ ├── select_edk_bin_dir.cmake │ ├── configure_build_system.cmake │ └── ensure_basetools.cmake ├── generic │ ├── core_count.cmake │ ├── helper_functions.cmake │ ├── include_edk2.cmake │ ├── package_build_api.cmake │ └── detect_python.cmake ├── linux │ ├── detect_tool_chain.cmake │ └── linux_defines.cmake ├── mac │ ├── detect_tool_chain.cmake │ └── mac_defines.cmake └── windows │ ├── select_edk_bin_dir.cmake │ ├── build_abi.cmake │ ├── configure_build_system.cmake │ ├── windows_defines.cmake │ ├── ensure_base_tools.cmake │ ├── detect_clang.cmake │ ├── detect_nasm.cmake │ └── detect_visual_studio.cmake ├── .github ├── FUNDING.yml └── workflows │ └── cmake.yml ├── CMakeLists.txt ├── README.md ├── LICENSE.GPL-2.0 └── scripts └── cmake └── detect_visual_studio.py /.gitignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | .vscode/* 3 | -------------------------------------------------------------------------------- /uefi_apps/LiorPkg/Include/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Propriatary Comercial License 2 | OR GPL-2.0 3 | -------------------------------------------------------------------------------- /documentation/dev_notes.md: -------------------------------------------------------------------------------- 1 | # Notes and Guideline for developers 2 | 3 | ## Cmake variables 4 | 5 | ### Naming convention 6 | 7 | `snake_case` for local/temp use variables. 8 | `SCREAMING_SNAKE_CASE` for user configurable variables or global variables of configuration variables. 9 | 10 | ### Usage of Cmake Cache 11 | 12 | TBD 13 | ## Tree Hiracy 14 | 15 | TBD 16 | -------------------------------------------------------------------------------- /uefi_apps/lior_pkg.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | # the name of the package, this must be idendical to the name of the package dir 3 | set(PACKAGE_NAME LiorPkg) 4 | 5 | # build arguments for edk2 build system 6 | set(BUILD_ARGS 7 | --arch=X64 # architecture to compile to 8 | --platform=LiorPkg/lior.dsc # the platform to compile 9 | # --module=LiorPkg/Lior/lior.inf # the specific module to compile 10 | -n ${CORE_COUNT} # amount of threads 11 | --tagname=${TOOL_CHAIN} # tool chain to use 12 | ) 13 | # this would create a target for the package 14 | add_package(${PACKAGE_NAME} ${BUILD_ARGS}) 15 | 16 | -------------------------------------------------------------------------------- /cmake_files/unix/build_abi.cmake: -------------------------------------------------------------------------------- 1 | SET(NEWLINE_STYLE "UNIX") 2 | 3 | function(generate_build_script CONTENT_VAR) 4 | # export the configuration variables 5 | set(EXPORTED_ENV "") 6 | foreach(var_name ${BUILD_ENV_VARIABLES}) 7 | set(var_value "${${var_name}}") 8 | string(APPEND EXPORTED_ENV "\n" "export ${var_name}=\"${var_value}\"") 9 | endforeach() 10 | 11 | string(JOIN "\n" script_content 12 | "#!${SHELL_CMD}" 13 | "${EXPORTED_ENV}" 14 | "export PATH=${EDK_BIN_WRAPPERS}:$PATH" 15 | "echo build $@" 16 | "build $@" 17 | ) 18 | 19 | set(${CONTENT_VAR} "${script_content}" PARENT_SCOPE) 20 | endfunction() 21 | -------------------------------------------------------------------------------- /cmake_files/generic/core_count.cmake: -------------------------------------------------------------------------------- 1 | # brief: detects system's core count for ideal compilation 2 | # in variables: None 3 | # out variables: 4 | # CORE_COUNT - CACHED the amount of cores to be used in the build process 5 | 6 | if(NOT DEFINED CORE_COUNT) 7 | include(ProcessorCount) 8 | # get core count 9 | ProcessorCount(CPU_CORES) 10 | 11 | # set the total cores as 1 less than the actual cores avaible 12 | if(CPU_CORES GREATER 1) 13 | math(EXPR N "${CPU_CORES} - 1" OUTPUT_FORMAT DECIMAL) 14 | else() 15 | # if geting the total cpu cores failes, default to 1 16 | set(N 1) 17 | endif() 18 | set(CORE_COUNT ${N} CACHE STRING "total cpu treads to use") 19 | endif() 20 | -------------------------------------------------------------------------------- /cmake_files/generic/helper_functions.cmake: -------------------------------------------------------------------------------- 1 | #brief: some helper functions 2 | if(NOT DEFINED __CMAKE__HELPER_FINCTIONS) # prevent multiple inclusions 3 | set(__CMAKE__HELPER_FINCTIONS TRUE) 4 | 5 | function(check_required_variables_defined variables) 6 | cmake_path(GET CMAKE_CURRENT_LIST_FILE FILENAME file_name) 7 | foreach(var_name ${variables}) 8 | if(NOT DEFINED ${var_name}) 9 | message(SEND_ERROR "${var_name} must be defined in order to use ${file_name}") 10 | endif() 11 | endforeach() 12 | endfunction() 13 | 14 | function(set_variable_to_native_path var_name) 15 | cmake_path(CONVERT "${${var_name}}" TO_NATIVE_PATH_LIST result NORMALIZE) 16 | set(${var_name} ${result} PARENT_SCOPE) 17 | endfunction() 18 | 19 | 20 | endif() # no code after this line 21 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [lersi] 4 | # patreon: # Replace with a single Patreon username 5 | # open_collective: # Replace with a single Open Collective username 6 | # ko_fi: # Replace with a single Ko-fi username 7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | # liberapay: # Replace with a single Liberapay username 10 | # issuehunt: # Replace with a single IssueHunt username 11 | # otechie: # Replace with a single Otechie username 12 | # lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /uefi_apps/LiorPkg/Lior/lior.inf: -------------------------------------------------------------------------------- 1 | [Defines] 2 | INF_VERSION = 0x00010005 3 | # BASE_NAME = LiorDriver 4 | BASE_NAME = LiorApp 5 | FILE_GUID = 539b1c67-0fd1-307d-8437-601f66d0bf1a 6 | # MODULE_TYPE = UEFI_DRIVER # use this for compiling a driver 7 | MODULE_TYPE = UEFI_APPLICATION 8 | ENTRY_POINT = lior_main 9 | 10 | # 11 | # The following information is for reference only and not required by the 12 | # build tools. 13 | # 14 | # VALID_ARCHITECTURES = IA32 X64 IPF EBC 15 | # 16 | ## 17 | [Sources.X64] # list here source files for the X64 architecture 18 | HelloWorld.c 19 | ## 20 | [Packages] # list here the packeges that your module depends on 21 | MdePkg/MdePkg.dec 22 | 23 | ## 24 | [LibraryClasses] # list here the library classes that you want to use 25 | UefiBootServicesTableLib 26 | # UefiDriverEntryPoint 27 | UefiApplicationEntryPoint 28 | UefiLib 29 | DebugLib 30 | -------------------------------------------------------------------------------- /cmake_files/linux/detect_tool_chain.cmake: -------------------------------------------------------------------------------- 1 | if(NOT DEFINED TOOL_CHAIN) 2 | # executing these commands in pipe will get darwin major version 3 | execute_process( 4 | COMMAND gcc --version 5 | COMMAND head -n 1 6 | COMMAND awk "{print $4}" 7 | OUTPUT_VARIABLE GCC_VERSION 8 | ) 9 | 10 | 11 | if(${GCC_VERSION} VERSION_LESS 4.8) 12 | # edk2 requires gcc 4.8 and later 13 | message(FATAL_ERROR "EDK2 required gcc version of 4.8 or later") 14 | elseif(${GCC_VERSION} VERSION_LESS 4.9) 15 | # gcc is version 4.8.x 16 | set(TOOL_CHAIN "GCC48" CACHE INTERNAL "") 17 | elseif(${GCC_VERSION} VERSION_LESS 5.0) 18 | # gcc is version 4.9.x 19 | set(TOOL_CHAIN "GCC49" CACHE INTERNAL "") 20 | else() 21 | # gcc is version 5.0 or later 22 | set(TOOL_CHAIN "GCC5" CACHE INTERNAL "") 23 | endif() 24 | 25 | endif() 26 | message(NOTICE "using toolchain: ${TOOL_CHAIN}") 27 | set(TARGET_TOOLS "${TOOL_CHAIN}") 28 | -------------------------------------------------------------------------------- /cmake_files/mac/detect_tool_chain.cmake: -------------------------------------------------------------------------------- 1 | 2 | if(NOT DEFINED TOOL_CHAIN) 3 | # executing these commands in pipe will get darwin major version 4 | execute_process( 5 | COMMAND uname -r 6 | OUTPUT_VARIABLE DARWIN_VERSION 7 | ) 8 | message(NOTICE "darwin version: ${DARWIN_VERSION}") 9 | # different darwin versions need different toolchains 10 | # note that "Darwin version" ≠ "OS X version" (i.e OS X Yosemite 10.10.2 has Darwin version 14) 11 | if (${DARWIN_VERSION} VERSION_LESS 10) 12 | # these old mac os versions are not supported by edk's build system 13 | message(FATAL_ERROR "this macos version is not supported please upgrade to a newer version") 14 | elseif(${DARWIN_VERSION} VERSION_LESS 11) # only major 10 15 | set(TOOL_CHAIN "XCODE32" CACHE INTERNAL "") 16 | elseif(${DARWIN_VERSION} VERSION_LESS 13) # only majors 11 and 12 17 | set(TOOL_CHAIN "XCLANG" CACHE INTERNAL "") 18 | else() # major 13 and forward 19 | set(TOOL_CHAIN "XCODE5" CACHE INTERNAL "") 20 | endif() 21 | endif() 22 | message(NOTICE "using toolchain: ${TOOL_CHAIN}") 23 | set(TARGET_TOOLS "${TOOL_CHAIN}") 24 | -------------------------------------------------------------------------------- /cmake_files/unix/select_edk_bin_dir.cmake: -------------------------------------------------------------------------------- 1 | #brief: selects edk bin wrappers based on system installation 2 | # in variables: 3 | # EDK_TOOLS_PATH - path to edk base tools repo 4 | # PYTHON_COMMAND - path/name of the python command to use 5 | # out variables: 6 | # EDK_BIN_WRAPPERS - CACHED INTERNAL path to edk bin wrappers folder 7 | 8 | set(_must_be_defined 9 | EDK_TOOLS_PATH 10 | PYTHON_COMMAND 11 | ) 12 | 13 | include(cmake_files/generic/helper_functions.cmake) 14 | check_required_variables_defined("${_must_be_defined}") #note the argument must be inside quotation marks so the list will be delivered as a single variable 15 | unset(_must_be_defined) # make sure does not leaks to other files 16 | 17 | if(NOT DEFINED EDK_BIN_WRAPPERS) 18 | execute_process( 19 | COMMAND ${PYTHON_COMMAND} -c "import edk2basetools" 20 | RESULT_VARIABLE python_result 21 | OUTPUT_QUIET 22 | ERROR_QUIET 23 | ) 24 | if(${python_result} EQUAL 0) 25 | set(EDK_BIN_WRAPPERS ${EDK_TOOLS_PATH}/BinPipWrappers/PosixLike CACHE INTERNAL "") 26 | else() 27 | set(EDK_BIN_WRAPPERS ${EDK_TOOLS_PATH}/BinWrappers/PosixLike CACHE INTERNAL "") 28 | endif() 29 | endif() 30 | -------------------------------------------------------------------------------- /cmake_files/windows/select_edk_bin_dir.cmake: -------------------------------------------------------------------------------- 1 | #brief: selects edk bin wrappers based on system installation 2 | # in variables: 3 | # EDK_TOOLS_PATH - path to edk base tools repo 4 | # PYTHON_COMMAND - path/name of the python command to use 5 | # out variables: 6 | # EDK_BIN_WRAPPERS - CACHED INTERNAL path to edk bin wrappers folder 7 | 8 | set(_must_be_defined 9 | EDK_TOOLS_PATH 10 | PYTHON_COMMAND 11 | ) 12 | 13 | include(cmake_files/generic/helper_functions.cmake) 14 | check_required_variables_defined("${_must_be_defined}") #note the argument must be inside quotation marks so the list will be delivered as a single variable 15 | unset(_must_be_defined) # make sure does not leaks to other files 16 | 17 | if(NOT DEFINED EDK_BIN_WRAPPERS) 18 | set_variable_to_native_path(EDK_TOOLS_PATH) 19 | execute_process( 20 | COMMAND ${PYTHON_COMMAND} -c "import edk2basetools" 21 | RESULT_VARIABLE python_result 22 | OUTPUT_QUIET 23 | ERROR_QUIET 24 | ) 25 | if(${python_result} EQUAL 0) 26 | set(EDK_BIN_WRAPPERS "${EDK_TOOLS_PATH}\\BinPipWrappers\\WindowsLike" CACHE INTERNAL "") 27 | else() 28 | set(EDK_BIN_WRAPPERS "${EDK_TOOLS_PATH}\\BinWrappers\\WindowsLike" CACHE INTERNAL "") 29 | endif() 30 | endif() 31 | -------------------------------------------------------------------------------- /uefi_apps/LiorPkg/lior.dec: -------------------------------------------------------------------------------- 1 | # this file is optional and not neccesary 2 | 3 | [Defines] 4 | DEC_SPECIFICATION = 0x00010005 5 | PACKAGE_NAME = Lior 6 | PACKAGE_GUID = c9df5526-0164-4313-89d4-375731bb0448 7 | PACKAGE_VERSION = 0.1 8 | 9 | [Includes] 10 | Include #Package Include directory 11 | 12 | [LibraryClasses] 13 | ## Library class name is same to library header file name 14 | OneClassLib|Include/Library/OneClassLib.h 15 | 16 | [Guids] 17 | 18 | #GuidCName = {xxxxxxxx,xxxx,xxxx,{xx,xx,xx,xx,xx,xx,xx,xx}}, 19 | [Ppis] 20 | 21 | #PpiGuidCName = {xxxxxxxx,xxxx,xxxx,{xx,xx,xx,xx,xx,xx,xx,xx}}, 22 | [Protocols] 23 | 24 | #ProtocolGuidCName = {xxxxxxxx,xxxx,xxxx,{xx,xx,xx,xx,xx,xx,xx,xx}}, 25 | [PcdsFeatureFlag] #FeatureFlag PCD is BOOLEAN type, the value is TRUR or FALSE. 26 | 27 | #PcdTokenSpaceCGuidName.PcdName|TRUE|BOOLEAN|TokenNumber 28 | #PcdTokenSpaceCGuidName.PcdName|FALSE|BOOLEAN|TokenNumber 29 | [PcdsFixedAtBuild] 30 | 31 | #PcdTokenSpaceCGuidName.PcdName|DefaultValue|DataType|TokenNumber 32 | [PcdsPatchableInModule] 33 | 34 | #PcdTokenSpaceCGuidName.PcdName|DefaultValue|DataType|TokenNumber 35 | [PcdsDynamic] 36 | 37 | #PcdTokenSpaceCGuidName.PcdName|DefaultValue|DataType|TokenNumber 38 | [PcdsDynamicEx] 39 | #PcdTokenSpaceCGuidName.PcdName|DefaultValue|DataType|TokenNumber 40 | -------------------------------------------------------------------------------- /cmake_files/generic/include_edk2.cmake: -------------------------------------------------------------------------------- 1 | #brief: integrates edk2 source repo into the build tree 2 | # input variables: None 3 | # out variables: 4 | # EDK2_SOURCE - the full path to edk2 repo root dir 5 | cmake_minimum_required(VERSION 3.17) 6 | include(FetchContent) 7 | 8 | # checks if we got a repo from user, if not get the repo from github 9 | if(NOT DEFINED LOCAL_EDK2) 10 | set(EDK_REPO https://github.com/tianocore/edk2.git CACHE STRING "") 11 | else() 12 | set(EDK_REPO ${LOCAL_EDK2} CACHE INTERNAL "") # note that this could be also a remote repo 13 | endif() 14 | 15 | # lets the user configure it's own edk2 tag to work with 16 | set(EDK2_TAG edk2-stable202205 CACHE STRING "the tag or commit of edk2 repo to use") # default tag 17 | 18 | message(NOTICE "using edk2 repo: ${EDK_REPO}") 19 | message(NOTICE "using git tag: ${EDK2_TAG}") 20 | 21 | # fetches the repo 22 | FetchContent_Declare( 23 | EDK2 24 | GIT_REPOSITORY ${EDK_REPO} 25 | GIT_TAG ${EDK2_TAG} 26 | GIT_SUBMODULES_RECURSE FALSE # for some problems with cmake cloning 27 | GIT_PROGRESS TRUE # show the progress of the repo cloning 28 | ) 29 | FetchContent_Populate(EDK2) 30 | 31 | 32 | # sets the source directory into a more redable name 33 | set(EDK2_SOURCE ${edk2_SOURCE_DIR}) # cmake will make the repo name lowercase 34 | 35 | -------------------------------------------------------------------------------- /cmake_files/mac/mac_defines.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | ## 3 | # Globals 4 | ## 5 | set(BUILD_ENV_VARIABLES PACKAGES_PATH) 6 | set(BUILD_SCRIPT _build.sh) 7 | string(JOIN ":" PACKAGES_PATH ${PACKAGES_PATH}) 8 | set(SHELL_CMD "/bin/zsh") 9 | set(SHELL_EXECUTE_ARG "-c") 10 | 11 | ## 12 | # decide which tool chain to use 13 | ## 14 | include(cmake_files/mac/detect_tool_chain.cmake) 15 | list(APPEND BUILD_ENV_VARIABLES TARGET_TOOLS) 16 | 17 | ## 18 | # set esential data 19 | ## 20 | set(EDK_TOOLS_PATH ${EDK2_SOURCE}/BaseTools) 21 | set(WORKSPACE ${CMAKE_CURRENT_BINARY_DIR}) 22 | include(cmake_files/generic/detect_python.cmake) 23 | list(APPEND BUILD_ENV_VARIABLES WORKSPACE PYTHON_COMMAND EDK_TOOLS_PATH) 24 | 25 | ## 26 | # make sure that edk2 build system is configured 27 | ## 28 | set(CONF_PATH ${CMAKE_BINARY_DIR}/conf CACHE PATH "where to save configuration for EDK build tools") 29 | list(APPEND BUILD_ENV_VARIABLES CONF_PATH) 30 | include(cmake_files/unix/configure_build_system.cmake) 31 | 32 | ## 33 | # make sure base tools is compiled 34 | ## 35 | include(cmake_files/unix/ensure_basetools.cmake) 36 | 37 | ## 38 | # select which bin dir to use 39 | ## 40 | include(cmake_files/unix/select_edk_bin_dir.cmake) 41 | 42 | ## 43 | # define interface functions for the build abi 44 | ## 45 | include(cmake_files/unix/build_abi.cmake) 46 | -------------------------------------------------------------------------------- /cmake_files/linux/linux_defines.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | ## 3 | # Globals 4 | ## 5 | set(BUILD_ENV_VARIABLES PACKAGES_PATH) 6 | set(BUILD_SCRIPT _build.sh) 7 | string(JOIN ":" PACKAGES_PATH ${PACKAGES_PATH}) 8 | set(SHELL_CMD "/bin/bash") 9 | set(SHELL_EXECUTE_ARG "-c") 10 | 11 | ## 12 | # decide which tool chain to use 13 | ## 14 | include(cmake_files/linux/detect_tool_chain.cmake) 15 | list(APPEND BUILD_ENV_VARIABLES TARGET_TOOLS) 16 | 17 | ## 18 | # set esential data 19 | ## 20 | set(EDK_TOOLS_PATH ${EDK2_SOURCE}/BaseTools) 21 | set(WORKSPACE ${CMAKE_CURRENT_BINARY_DIR}) 22 | include(cmake_files/generic/detect_python.cmake) 23 | list(APPEND BUILD_ENV_VARIABLES WORKSPACE PYTHON_COMMAND EDK_TOOLS_PATH) 24 | 25 | ## 26 | # make sure that edk2 build system is configured 27 | ## 28 | set(CONF_PATH ${CMAKE_BINARY_DIR}/conf CACHE PATH "where to save configuration for EDK build tools") 29 | list(APPEND BUILD_ENV_VARIABLES CONF_PATH) 30 | include(cmake_files/unix/configure_build_system.cmake) 31 | 32 | ## 33 | # make sure base tools is compiled 34 | ## 35 | include(cmake_files/unix/ensure_basetools.cmake) 36 | 37 | ## 38 | # select which bin dir to use 39 | ## 40 | include(cmake_files/unix/select_edk_bin_dir.cmake) 41 | 42 | ## 43 | # define interface functions for the build abi 44 | ## 45 | include(cmake_files/unix/build_abi.cmake) 46 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.12) 2 | 3 | project(edk2_template LANGUAGES C ASM) 4 | 5 | # include general files 6 | include(cmake_files/generic/helper_functions.cmake) 7 | 8 | # set(LOCAL_EDK2 ) # this variable could also be be transfered to cmake in the command line 9 | # imports edk2 project 10 | include(cmake_files/generic/include_edk2.cmake) 11 | # get the cpu core count 12 | include(cmake_files/generic/core_count.cmake) 13 | 14 | # specifiece the dir that contains sources for EDK2 15 | set(PACKAGE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/uefi_apps) 16 | set(PACKAGES_PATH ${PACKAGE_DIR} ${EDK2_SOURCE}) 17 | set(CMAKE_SCRIPTS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/scripts/cmake) 18 | 19 | # platform specific modules 20 | if(WIN32) 21 | # windows platform (also 64 bit) 22 | include(cmake_files/windows/windows_defines.cmake) 23 | elseif(APPLE) 24 | # mac platform 25 | include(cmake_files/mac/mac_defines.cmake) 26 | elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") 27 | # linux platform 28 | include(cmake_files/linux/linux_defines.cmake) 29 | else() 30 | message("${CMAKE_SYSTEM_NAME}") 31 | message(FATAL_ERROR "current platform is not supported") 32 | endif() 33 | 34 | 35 | 36 | # include functions for creating targets 37 | include(cmake_files/generic/package_build_api.cmake) 38 | 39 | 40 | # list all packages that we want to compile 41 | include(uefi_apps/lior_pkg.cmake) 42 | 43 | -------------------------------------------------------------------------------- /cmake_files/windows/build_abi.cmake: -------------------------------------------------------------------------------- 1 | set(NEWLINE_STYLE "WIN32") 2 | 3 | function(generate_build_script CONTENT_VAR) 4 | # export the configuration variables 5 | set(EXPORTED_ENV "") 6 | foreach(var_name ${BUILD_ENV_VARIABLES}) 7 | set(var_value "${${var_name}}") 8 | set_variable_to_native_path(var_value) 9 | string(FIND "${var_value}" " " has_space) 10 | if(${has_space} GREATER_EQUAL 0) 11 | string(APPEND EXPORTED_ENV "\n" "set ${var_name}=\"${var_value}\"") 12 | else() 13 | string(APPEND EXPORTED_ENV "\n" "set ${var_name}=${var_value}") 14 | endif() 15 | endforeach() 16 | 17 | string(JOIN "\n" script_content 18 | "@echo off" 19 | # something for python cache 20 | "set PYTHONHASHSEED=1" 21 | # for using clang 22 | "@set CLANG_HOST_BIN=n" 23 | # to set visual studio configuration 24 | "call \"${VS_ENVIRONMENT_SCRIPT}\"" 25 | # to set things based on visual studio configuration 26 | "call \"${BASE_TOOLS_PATH}\\set_vsprefix_envs.bat\"" 27 | "${EXPORTED_ENV}" 28 | # add base tools to path 29 | "set PATH=${EDK_TOOLS_BIN};${EDK_BIN_WRAPPERS};\%PATH\%" 30 | # add python base tools to python path 31 | "set PYTHONPATH=${BASETOOLS_PYTHON_SOURCE};%PYTHONPATH%" 32 | "echo build \%*" 33 | "build \%*" 34 | ) 35 | 36 | set(${CONTENT_VAR} "${script_content}" PARENT_SCOPE) 37 | endfunction() 38 | -------------------------------------------------------------------------------- /cmake_files/windows/configure_build_system.cmake: -------------------------------------------------------------------------------- 1 | #brief: makes sure that edk2's build system is configured 2 | # in variables: 3 | # CONF_PATH - a path to save edk's build configuration 4 | # BUILD_ENV_VARIABLES - variables that are configuring the EDK2 build system 5 | # EDK_TOOLS_PATH - path to basetools repo dir 6 | # out variables: None 7 | 8 | set(_must_be_defined 9 | CONF_PATH 10 | BUILD_ENV_VARIABLES 11 | EDK_TOOLS_PATH 12 | ) 13 | 14 | include(cmake_files/generic/helper_functions.cmake) 15 | check_required_variables_defined("${_must_be_defined}") #note the argument must be inside quotation marks so the list will be delivered as a single variable 16 | unset(_must_be_defined) # make sure does not leaks to other files 17 | 18 | if((NOT EXISTS ${CONF_PATH}) OR (NOT EXISTS ${CONF_PATH}/tools_def.txt)) 19 | make_directory(${CONF_PATH}) 20 | set(ENV{RECONFIG} "TRUE") 21 | foreach(var_name ${BUILD_ENV_VARIABLES}) 22 | set_variable_to_native_path(${var_name}) 23 | set(ENV{${var_name}} "${${var_name}}") 24 | message(NOTICE "${var_name} = ${${var_name}}") 25 | endforeach() 26 | 27 | message("configuration does not exist, generating it") 28 | execute_process( 29 | COMMAND "${EDK_TOOLS_PATH}\\toolsetup.bat" Reconfig ${TOOL_CHAIN} 30 | OUTPUT_VARIABLE conf_result 31 | ERROR_VARIABLE conf_error 32 | ECHO_OUTPUT_VARIABLE 33 | ECHO_ERROR_VARIABLE 34 | COMMAND_ERROR_IS_FATAL ANY 35 | COMMAND_ECHO STDOUT 36 | ) 37 | endif() 38 | -------------------------------------------------------------------------------- /cmake_files/unix/configure_build_system.cmake: -------------------------------------------------------------------------------- 1 | #brief: makes sure that edk2's build system is configured 2 | # in variables: 3 | # SHELL_CMD - the name\fullpath of the shell commad to execute 4 | # SHELL_EXECUTE_ARG - the argument that allows to execute one command in the shell 5 | # CONF_PATH - a path to save edk's build configuration 6 | # BUILD_ENV_VARIABLES - variables that are configuring the EDK2 build system 7 | # EDK_TOOLS_PATH - path to basetools repo dir 8 | # out variables: None 9 | 10 | set(_must_be_defined 11 | SHELL_CMD 12 | SHELL_EXECUTE_ARG 13 | CONF_PATH 14 | BUILD_ENV_VARIABLES 15 | EDK_TOOLS_PATH 16 | ) 17 | 18 | include(cmake_files/generic/helper_functions.cmake) 19 | check_required_variables_defined("${_must_be_defined}") #note the argument must be inside quotation marks so the list will be delivered as a single variable 20 | unset(_must_be_defined) # make sure does not leaks to other files 21 | 22 | if((NOT EXISTS ${CONF_PATH}) OR (NOT EXISTS ${CONF_PATH}/tools_def.txt)) 23 | make_directory(${CONF_PATH}) 24 | set(ENV{RECONFIG} "TRUE") 25 | foreach(var_name ${BUILD_ENV_VARIABLES}) 26 | set(ENV{${var_name}} "${${var_name}}") 27 | endforeach() 28 | execute_process( 29 | COMMAND ${SHELL_CMD} ${SHELL_EXECUTE_ARG} "source ${EDK_TOOLS_PATH}/BuildEnv" 30 | OUTPUT_VARIABLE conf_result 31 | ERROR_VARIABLE conf_error 32 | ECHO_OUTPUT_VARIABLE 33 | ECHO_ERROR_VARIABLE 34 | COMMAND_ERROR_IS_FATAL ANY 35 | ) 36 | endif() 37 | 38 | 39 | -------------------------------------------------------------------------------- /cmake_files/unix/ensure_basetools.cmake: -------------------------------------------------------------------------------- 1 | #brief: makes sure that edk2's build system is configured 2 | # in variables: 3 | # EDK_TOOLS_PATH - path to edk base tools repo 4 | # PYTHON_COMMAND - path/name of the python command to use 5 | # out variables: 6 | # BASE_TOOLS_ARTIFACTS - the path to base tools compiled binaries 7 | # BASETOOLS_FAILED - CACHED INTERNAL for indicating that even if the artifact exists it needs recompile 8 | 9 | set(_must_be_defined 10 | EDK_TOOLS_PATH 11 | PYTHON_COMMAND 12 | ) 13 | 14 | include(cmake_files/generic/helper_functions.cmake) 15 | check_required_variables_defined("${_must_be_defined}") #note the argument must be inside quotation marks so the list will be delivered as a single variable 16 | unset(_must_be_defined) # make sure does not leaks to other files 17 | 18 | set(BASE_TOOLS_ARTIFACTS ${EDK_TOOLS_PATH}/Source/C/bin) 19 | if(NOT EXISTS ${BASE_TOOLS_ARTIFACTS} OR BASETOOLS_FAILED) 20 | # build base tools if are not present 21 | set(ENV{PYTHON_COMMAND} ${PYTHON_COMMAND}) 22 | message(NOTICE "building base tools...") 23 | execute_process( 24 | COMMAND make -C ${EDK_TOOLS_PATH} 25 | OUTPUT_QUIET 26 | RESULT_VARIABLE build_result 27 | ) 28 | if(NOT ${build_result} EQUAL 0) 29 | execute_process( 30 | COMMAND make -C ${EDK_TOOLS_PATH} clean 31 | OUTPUT_QUIET 32 | ERROR_QUIET 33 | ) 34 | set(BASETOOLS_FAILED TRUE CACHE INTERNAL "basetools compilation failed last run") 35 | message(FATAL_ERROR "base tools build failed!") 36 | elseif() 37 | unset(BASETOOLS_FAILED CACHE) 38 | endif() 39 | endif() 40 | -------------------------------------------------------------------------------- /uefi_apps/LiorPkg/Lior/HelloWorld.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file HelloWorld.c 3 | * @author lersi, on github 4 | * @brief a dummy driver/app for demonstrating the build system 5 | * @version 0.1 6 | * @date 2022-03-17 7 | * 8 | * @copyright Copyright (c) lersi 2022 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | EFI_STATUS 17 | EFIAPI 18 | lior_main( 19 | IN EFI_HANDLE ImageHandle, 20 | IN EFI_SYSTEM_TABLE *SystemTable 21 | ) 22 | { 23 | EFI_STATUS Status; 24 | EFI_PHYSICAL_ADDRESS PhysicalBuffer; 25 | UINTN Pages; 26 | VOID *Buffer; 27 | 28 | Print(L"\n"); 29 | Pages = EFI_SIZE_TO_PAGES (SIZE_16KB); 30 | Status = SystemTable->BootServices->AllocatePages ( 31 | AllocateAnyPages, /* allocate pages in any address*/ 32 | EfiBootServicesData, /* the type of the memory to allocate*/ 33 | Pages, /* the amount of pages to allocate */ 34 | &PhysicalBuffer /* will contain the address of the pages */ 35 | ); 36 | if (EFI_ERROR (Status)) { 37 | Print(L"error allocating memory\n"); 38 | return Status; 39 | } 40 | /** 41 | * Convert the physical address to a pointer. 42 | * This method should work for all supported CPU architectures. 43 | */ 44 | Buffer = (VOID *)(UINTN)PhysicalBuffer; 45 | *(UINT64 *)Buffer = 0x4c657273; 46 | ((UINT8 *)Buffer)[4] = 105; 47 | /** 48 | * Free the allocated buffer 49 | */ 50 | Status = gBS->FreePages (PhysicalBuffer, Pages); 51 | if (EFI_ERROR (Status)) { 52 | Print(L"error freeing memory\n"); 53 | return Status; 54 | } 55 | Print(L"Success!\n"); 56 | return EFI_SUCCESS; 57 | } 58 | -------------------------------------------------------------------------------- /cmake_files/generic/package_build_api.cmake: -------------------------------------------------------------------------------- 1 | #brief: defines all helper functions for creating a build target for a package 2 | include(cmake_files/generic/helper_functions.cmake) 3 | 4 | function(internal_add_package PKG_NAME BUILD_ARGS) 5 | # list all files in our pkg 6 | file(GLOB_RECURSE PKG_SOURCE_FILES 7 | LIST_DIRECTORIES false 8 | ${PACKAGE_DIR}/${PKG_NAME}/** 9 | ) 10 | 11 | generate_build_script(script_content) 12 | set(SCRIPT_PATH ${CMAKE_CURRENT_BINARY_DIR}/${BUILD_SCRIPT}) 13 | set_variable_to_native_path(SCRIPT_PATH) 14 | file(GENERATE OUTPUT ${SCRIPT_PATH} 15 | CONTENT "${script_content}" 16 | FILE_PERMISSIONS OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE 17 | NEWLINE_STYLE ${NEWLINE_STYLE} 18 | ) 19 | message("build cmd: ${SCRIPT_PATH} ${BUILD_ARGS}") 20 | # create the target 21 | add_custom_target(${PKG_NAME} 22 | ${SCRIPT_PATH} ${BUILD_ARGS} 23 | SOURCES ${PKG_SOURCE_FILES} 24 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 25 | USES_TERMINAL 26 | ) 27 | endfunction() 28 | 29 | ## 30 | # description: this function creates a Cmake target for a package. 31 | # 32 | # arg1: PKG_NAME the name of the package to create a target for 33 | # arg2-n: BUILD_ARGS list of argument to pass to edk's build system 34 | # 35 | # this is a warper function that deals with sending lists to a function 36 | # as a bunch of variables instead of a list 37 | ## 38 | function(add_package PKG_NAME BUILD_ARGS) 39 | if(NOT EXISTS ${PACKAGE_DIR}/${PKG_NAME}) 40 | message(FATAL_ERROR "the packge ${PKG_NAME} does not exists in folder ${PACKAGE_DIR}") 41 | endif() 42 | set(BUILD_LIST "") 43 | list(APPEND BUILD_LIST ${BUILD_ARGS}) 44 | list(APPEND BUILD_LIST ${ARGN}) 45 | internal_add_package(${PKG_NAME} "${BUILD_LIST}") 46 | endfunction() 47 | -------------------------------------------------------------------------------- /cmake_files/windows/windows_defines.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | ## 3 | # Globals 4 | ## 5 | set(BUILD_SCRIPT _build.bat) # the name og the build script script to create 6 | set(BUILD_ENV_VARIABLES PACKAGES_PATH) # list containing all enviroment variables needed for configuration and build 7 | string(JOIN ";" PACKAGES_PATH ${PACKAGES_PATH}) 8 | set(DEFAULT_NASM_PATH "C:\\nasm") 9 | set(DEFAULT_CLANG_PATH "C:\\Program Files\\LLVM\\bin") 10 | set(SHELL_CMD "cmd") 11 | set(SHELL_EXECUTE_ARG "/C") 12 | 13 | ## 14 | # Helper functions 15 | ## 16 | include(cmake_files/generic/helper_functions.cmake) 17 | 18 | ## 19 | # set esential data 20 | ## 21 | set(EDK_TOOLS_PATH ${EDK2_SOURCE}/BaseTools) 22 | set_variable_to_native_path(EDK_TOOLS_PATH) 23 | set(BASE_TOOLS_PATH ${EDK_TOOLS_PATH}) 24 | set(WORKSPACE_TOOLS_PATH ${EDK_TOOLS_PATH}) 25 | set(BASETOOLS_PYTHON_SOURCE ${BASE_TOOLS_PATH}\\Source\\Python) 26 | set(WORKSPACE ${CMAKE_CURRENT_BINARY_DIR}) 27 | list(APPEND BUILD_ENV_VARIABLES WORKSPACE EDK_TOOLS_PATH BASE_TOOLS_PATH WORKSPACE_TOOLS_PATH) 28 | 29 | ## 30 | # find python 31 | ## 32 | include(cmake_files/generic/detect_python.cmake) 33 | list(APPEND BUILD_ENV_VARIABLES PYTHON_COMMAND) 34 | 35 | ## 36 | # find visual studio (toolchain) 37 | ## 38 | # detects vs environment configuration script and the tool chain tag 39 | include(cmake_files/windows/detect_visual_studio.cmake) 40 | set(TOOL_CHAIN ${_VS_TAG}) 41 | message(NOTICE "using toolchain: ${TOOL_CHAIN}") 42 | 43 | ## 44 | # find nasm 45 | ## 46 | include(cmake_files/windows/detect_nasm.cmake) 47 | if(DEFINED NASM_PREFIX) 48 | list(APPEND BUILD_ENV_VARIABLES NASM_PREFIX) 49 | endif() 50 | 51 | ## 52 | # find clang 53 | ## 54 | include(cmake_files/windows/detect_clang.cmake) 55 | if(DEFINED CLANG_BIN) 56 | list(APPEND BUILD_ENV_VARIABLES CLANG_BIN) 57 | endif() 58 | 59 | ## 60 | # make sure that edk2 build system is configured 61 | ## 62 | set(CONF_PATH ${CMAKE_BINARY_DIR}\\conf CACHE PATH "where to save configuration for EDK build tools") 63 | list(APPEND BUILD_ENV_VARIABLES CONF_PATH) 64 | include(cmake_files/windows/configure_build_system.cmake) 65 | 66 | ## 67 | # make sure base tools is compiled 68 | ## 69 | include(cmake_files/windows/ensure_base_tools.cmake) 70 | list(APPEND BUILD_ENV_VARIABLES EDK_TOOLS_BIN) 71 | 72 | ## 73 | # check which bin dir to use 74 | ## 75 | include(cmake_files/windows/select_edk_bin_dir.cmake) 76 | 77 | ## 78 | # define interface functions for the build abi 79 | ## 80 | include(cmake_files/windows/build_abi.cmake) 81 | -------------------------------------------------------------------------------- /cmake_files/windows/ensure_base_tools.cmake: -------------------------------------------------------------------------------- 1 | #brief: makes sure that edk2's build system is configured 2 | # in variables: 3 | # SHELL_CMD - the name\fullpath of the shell commad to execute 4 | # SHELL_EXECUTE_ARG - the argument that allows to execute one command in the shell 5 | # EDK_TOOLS_PATH - path to edk base tools repo 6 | # PYTHON_COMMAND - path/name of the python command to use 7 | # VS_ENVIRONMENT_SCRIPT - full path to a script file that add visual studio compiler to path 8 | # out variables: 9 | # BASE_TOOLS_ARTIFACTS - the path to base tools compiled binaries 10 | # BASETOOLS_FAILED - CACHED INTERNAL for indicating that even if the artifact exists it needs recompile 11 | # EDK_TOOLS_BIN - path to base tools binaries 12 | 13 | set(_must_be_defined 14 | SHELL_CMD 15 | SHELL_EXECUTE_ARG 16 | EDK_TOOLS_PATH 17 | PYTHON_COMMAND 18 | VS_ENVIRONMENT_SCRIPT 19 | ) 20 | 21 | include(cmake_files/generic/helper_functions.cmake) 22 | check_required_variables_defined("${_must_be_defined}") #note the argument must be inside quotation marks so the list will be delivered as a single variable 23 | unset(_must_be_defined) # make sure does not leaks to other files 24 | 25 | set(BASE_TOOLS_ARTIFACTS ${EDK_TOOLS_PATH}\\Bin\\Win32) 26 | if(NOT EXISTS ${BASE_TOOLS_ARTIFACTS}) 27 | #set esential variables needed by the build script 28 | foreach(var_name ${BUILD_ENV_VARIABLES}) 29 | set_variable_to_native_path(${var_name}) 30 | set(ENV{${var_name}} "${${var_name}}") 31 | message(NOTICE "${var_name} = ${${var_name}}") 32 | endforeach() 33 | 34 | message(NOTICE "building base tools...") 35 | set(ENV{PATH} "${BASE_TOOLS_ARTIFACTS};$ENV{PATH}") # some build steps relay on the artifacts of the previous steps, so add base tools bin dir to path 36 | string(CONCAT build_tools_cmd "${SHELL_CMD} ${SHELL_EXECUTE_ARG} \"${VS_ENVIRONMENT_SCRIPT}\"" 37 | " && ${EDK_TOOLS_PATH}\\toolsetup.bat ForceRebuild ${TOOL_CHAIN}" 38 | ) 39 | separate_arguments(build_tools_cmd WINDOWS_COMMAND ${build_tools_cmd}) 40 | execute_process( 41 | COMMAND ${build_tools_cmd} 42 | RESULT_VARIABLE build_result 43 | COMMAND_ECHO STDOUT 44 | ) 45 | # if the artifacts still does not exist, then the build must have failed 46 | if(NOT EXISTS ${BASE_TOOLS_ARTIFACTS}) 47 | message(FATAL_ERROR "base tools build failed!") 48 | endif() 49 | endif() 50 | set(EDK_TOOLS_BIN ${BASE_TOOLS_ARTIFACTS}) 51 | set_variable_to_native_path(EDK_TOOLS_BIN) 52 | -------------------------------------------------------------------------------- /cmake_files/windows/detect_clang.cmake: -------------------------------------------------------------------------------- 1 | #### 2 | # description: detects clang location. 3 | # author: Lior Shalmay 4 | # in variables: 5 | # SHELL_CMD - the name\fullpath of the shell commad to execute 6 | # SHELL_EXECUTE_ARG - the argument that allows to execute one command in the shell 7 | # CLANG_BIN_PATH - OPTIONAL user provided path to clang binary dir 8 | # DEFAULT_CLANG_PATH - a default path to where clang should probably be. 9 | # 10 | # out variables: 11 | # CLANG_BIN - CACHED OPTIONAL path to clang binary dir 12 | #### 13 | set(_must_be_defined 14 | SHELL_CMD 15 | SHELL_EXECUTE_ARG 16 | DEFAULT_CLANG_PATH 17 | ) 18 | 19 | include(cmake_files/generic/helper_functions.cmake) 20 | check_required_variables_defined("${_must_be_defined}") #note the argument must be inside quotation marks so the list will be delivered as a single variable 21 | unset(_must_be_defined) # make sure does not leaks to other files 22 | 23 | if(DEFINED CLANG_BIN_PATH) 24 | # sanity check 25 | if(NOT EXISTS ${CLANG_BIN_PATH}) 26 | message(SEND_ERROR "the path provided by `CLANG_BIN_PATH` does not exist!") 27 | endif() 28 | cmake_path(CONVERT ${CLANG_BIN_PATH} TO_NATIVE_PATH_LIST CLANG_BIN_PATH NORMALIZE) 29 | set(CLANG_BIN ${CLANG_BIN_PATH} CACHE INTERNAL "path to clang's bin dir" FORCE) 30 | elseif(NOT DEFINED CLANG_BIN) 31 | set(default_clang_exec ${DEFAULT_CLANG_PATH}\\clang.exe) 32 | # check default path first 33 | if(EXISTS ${default_clang_exec}) 34 | set(CLANG_BIN ${DEFAULT_CLANG_PATH} CACHE INTERNAL "path to clang's bin dir" FORCE) 35 | else() 36 | # try to get clang from path 37 | execute_process( # use vs enviroment script, to look also for visual studio's clang 38 | COMMAND cmd /C "${VS_ENVIRONMENT_SCRIPT}" && where clang 39 | OUTPUT_VARIABLE output 40 | RESULT_VARIABLE result 41 | ERROR_QUIET 42 | ) 43 | if(${result} EQUAL 0) 44 | string(REGEX MATCH "C:\\\\[A-Z,a-z, ,\\\\,\\(,\\),_,0-9,\\.]*\\.exe" clang_cmd_path ${output}) 45 | string(STRIP ${clang_cmd_path} clang_cmd_path) 46 | get_filename_component(clang_path ${clang_cmd_path} DIRECTORY) 47 | set(CLANG_BIN ${clang_path} CACHE INTERNAL "path to clang's bin dir" FORCE) 48 | else() 49 | message(WARNING "could not find clang, components that uses clang will fail to compile\nyou can specify clang's binary directory by setting `CLANG_BIN_PATH`") 50 | endif() 51 | endif() 52 | endif() 53 | -------------------------------------------------------------------------------- /cmake_files/windows/detect_nasm.cmake: -------------------------------------------------------------------------------- 1 | #### 2 | # description: detects nasm location. 3 | # author: Lior Shalmay 4 | # in variables: 5 | # SHELL_CMD - the name\fullpath of the shell commad to execute 6 | # SHELL_EXECUTE_ARG - the argument that allows to execute one command in the shell 7 | # NASM_PATH - OPTIONAL user provided path to nasm install dir 8 | # DEFAULT_NASM_PATH - a default path to where nasm should probably be. 9 | # 10 | # out variables: 11 | # NASM_PREFIX - CACHED OPTIONAL path to nasm install dir 12 | #### 13 | set(_must_be_defined 14 | SHELL_CMD 15 | SHELL_EXECUTE_ARG 16 | DEFAULT_NASM_PATH 17 | ) 18 | 19 | include(cmake_files/generic/helper_functions.cmake) 20 | check_required_variables_defined("${_must_be_defined}") #note the argument must be inside quotation marks so the list will be delivered as a single variable 21 | unset(_must_be_defined) # make sure does not leaks to other files 22 | 23 | if(DEFINED NASM_PATH) 24 | # sanity check 25 | if(NOT EXISTS ${NASM_PATH}) 26 | message(SEND_ERROR "the path provided by `NASM_PATH` does not exist!") 27 | endif() 28 | # make sure that the path ends with a backslash 29 | set_variable_to_native_path(NASM_PATH) 30 | string(REGEX MATCH ".$" last_char ${NASM_PATH}) 31 | if(NOT last_char STREQUAL "\\") 32 | set(NASM_PATH ${NASM_PATH}\\) 33 | endif() 34 | set(NASM_PREFIX ${NASM_PATH} CACHE INTERNAL "path to nasm insall dir" FORCE) 35 | elseif(NOT DEFINED NASM_PREFIX) 36 | # setting up for the first time 37 | set(default_nasm_exec "${DEFAULT_NASM_PATH}\\nasm.exe") 38 | # check for default location first 39 | if(EXISTS ${default_nasm_exec}) 40 | set(NASM_PREFIX ${DEFAULT_NASM_PATH}\\ CACHE INTERNAL "path to nasm insall dir" FORCE) 41 | else() 42 | # try to find nasm from path 43 | execute_process( 44 | COMMAND ${SHELL_CMD} ${SHELL_EXECUTE_ARG} where nasm 45 | OUTPUT_VARIABLE output 46 | ERROR_QUIET 47 | ECHO_OUTPUT_VARIABLE 48 | RESULT_VARIABLE run_result 49 | COMMAND_ECHO STDOUT 50 | ) 51 | if(${run_result} EQUAL 0) 52 | # found nasm 53 | string(STRIP ${output} nasm_cmd_path) 54 | get_filename_component(nasm_path ${nasm_cmd_path} DIRECTORY) 55 | set(NASM_PREFIX ${nasm_path}\\ CACHE INTERNAL "path to nasm insall dir" FORCE) 56 | else() 57 | message(WARNING "cound not find nasm, components that uses nasm will fail to compile\nyou can specify nasm's directory by setting `NASM_PATH`") 58 | endif() 59 | endif() 60 | endif() 61 | -------------------------------------------------------------------------------- /cmake_files/windows/detect_visual_studio.cmake: -------------------------------------------------------------------------------- 1 | #### 2 | # description: detects visual studio location, version and dev environment. 3 | # author: Lior Shalmay 4 | #### 5 | 6 | cmake_minimum_required(VERSION 3.20) 7 | set(force_vs_search FALSE) 8 | 9 | if(DEFINED CUSTOM_VS_INSTALLER_PATHS) 10 | if(NOT ${CUSTOM_VS_INSTALLER_PATHS} STREQUAL ${_CUSTOM_VS_INSTALLER_PATHS}) 11 | # enables users to add there own paths 12 | set(_CUSTOM_VS_INSTALLER_PATHS ${CUSTOM_VS_INSTALLER_PATHS} CACHE INTERNAL "list of paths to search for visual studio installer, seperated by colon" FORCE) 13 | set(force_vs_search TRUE) 14 | unset(_CUSTOM_VS_DIR CACHE) 15 | endif() 16 | endif() 17 | 18 | if(DEFINED VS_TAG) 19 | if(NOT ${VS_TAG} STREQUAL ${_VS_TAG}) 20 | # enables users to select specific vs version 21 | set(_VS_TAG ${VS_TAG} CACHE INTERNAL "visual studio version tag i.e VS2019" FORCE) 22 | set(force_vs_search TRUE) 23 | endif() 24 | endif() 25 | 26 | if(DEFINED CUSTOM_VS_DIR) 27 | if(DEFINED CUSTOM_VS_INSTALLER_PATHS) 28 | message(FATAL_ERROR "'CUSTOM_VS_DIR' and 'CUSTOM_VS_INSTALLER_PATHS' cannot be defined at the same time") 29 | endif() 30 | if(NOT ${VS_TAG} STREQUAL ${_VS_TAG}) 31 | # enables users to deliver custom vs location 32 | set(_CUSTOM_VS_DIR ${VS_TAG} CACHE INTERNAL "visual studio install dir location" FORCE) 33 | set(force_vs_search TRUE) 34 | unset(_CUSTOM_VS_INSTALLER_PATHS CACHE) 35 | endif() 36 | endif() 37 | 38 | set(force_vs_search TRUE) 39 | unset(_VS_TAG CACHE) 40 | if(${force_vs_search} OR NOT DEFINED VS_ENVIRONMENT_SCRIPT) 41 | set(args "") 42 | # add the appropriet flags for each defined configuration variable 43 | if(DEFINED _CUSTOM_VS_INSTALLER_PATHS) 44 | set(args "${args} --installer-paths ${_CUSTOM_VS_INSTALLER_PATHS}") 45 | endif() 46 | if(DEFINED _VS_TAG) 47 | set(args "${args} --vs-tag ${_VS_TAG}") 48 | endif() 49 | if(DEFINED _CUSTOM_VS_DIR) 50 | set(args "${args} --vs-path ${_CUSTOM_VS_DIR}") 51 | endif() 52 | 53 | # get the desired file path 54 | execute_process( 55 | COMMAND cmd /C ${PYTHON_COMMAND} ${CMAKE_SCRIPTS_DIR}/detect_visual_studio.py ${args} 56 | OUTPUT_VARIABLE output 57 | COMMAND_ERROR_IS_FATAL ANY 58 | OUTPUT_STRIP_TRAILING_WHITESPACE 59 | ) 60 | string(REPLACE "," ";" outputs ${output}) 61 | 62 | list(GET outputs 0 vs_script) 63 | list(GET outputs 1 vs_tag) 64 | set(VS_ENVIRONMENT_SCRIPT ${vs_script} CACHE INTERNAL "the script that defines all visual studio's environment" FORCE) 65 | set(_VS_TAG ${vs_tag} CACHE INTERNAL "visual studio version tag i.e VS2019" FORCE) 66 | endif() 67 | 68 | -------------------------------------------------------------------------------- /cmake_files/generic/detect_python.cmake: -------------------------------------------------------------------------------- 1 | # brief detects python executable of version 3.7 and above 2 | # input variables: None 3 | # out variables: 4 | # PYTHON_COMMAND - CACHED full path to python interperter or name of python command in path 5 | 6 | # the minimum compatiable python version 7 | set(_MINIMUM_PYTHON_VERSION "3.7") 8 | # list of predeterment names of the python command to look for 9 | set(_PYTHON_3_COMMANDS 10 | "py -3" 11 | "python" 12 | "python3" 13 | "python3.8" 14 | "python3.9" 15 | "python3.10" 16 | ) 17 | 18 | 19 | if(NOT DEFINED PYTHON_COMMAND) 20 | # first try to find default python command names in path 21 | set(python_found FALSE) 22 | foreach(python_command_name ${_PYTHON_3_COMMANDS}) 23 | # for each command name check if it exists and suitable 24 | string(REPLACE " " ":" _command "${python_command_name}") 25 | execute_process( 26 | COMMAND ${_command} --version 27 | RESULT_VARIABLE result 28 | OUTPUT_VARIABLE output 29 | ERROR_QUIET 30 | ) 31 | if(result EQUAL 0 AND NOT "${output}" STREQUAL "") 32 | # the python command has executed successfuly (it exits) 33 | string(REPLACE " " ";" outputs "${output}") 34 | list(GET outputs 1 version) 35 | # check if the python version matches our requirments 36 | if(${version} VERSION_GREATER_EQUAL ${_MINIMUM_PYTHON_VERSION}) 37 | message(NOTICE "found python command as: ${python_command_name}") 38 | # save the command name into cache 39 | set(PYTHON_COMMAND ${python_command_name} CACHE STRING "path to python interperter or name of python command" FORCE) 40 | set(python_found TRUE) 41 | break() # we found what we need 42 | endif() 43 | endif() 44 | endforeach() 45 | 46 | if(NOT ${python_found}) 47 | # python command was not found, find it using cmake. 48 | # searching for python command location 49 | find_package (Python3 ${_MINIMUM_PYTHON_VERSION} QUIET COMPONENTS Interpreter) 50 | if(NOT ${Python3_Interpreter_FOUND}) 51 | # python location was not found 52 | string(CONCAT error_msg 53 | "could not find the location of the python command (or your python is older than 3.7), \n" 54 | "please use `-DPYTHON_COMMAND=`\n" 55 | "to declare the python interperter for use" 56 | ) 57 | message(SEND_ERROR ${error_msg}) 58 | else() 59 | # show python loocation to user, and save to cache 60 | cmake_path(CONVERT ${Python3_EXECUTABLE} TO_NATIVE_PATH_LIST python3_path NORMALIZE) 61 | message(NOTICE "found python command at: ${python3_path}") 62 | set(PYTHON_COMMAND "${python3_path}" CACHE STRING "path to python interperter or name of python command" FORCE) 63 | endif() 64 | endif() 65 | endif() 66 | message(NOTICE "PYTHON_COMMAND: ${PYTHON_COMMAND}") 67 | -------------------------------------------------------------------------------- /uefi_apps/LiorPkg/lior.dsc: -------------------------------------------------------------------------------- 1 | [Defines] 2 | PLATFORM_NAME = Lior 3 | PLATFORM_GUID = aaddf6e3-7ed7-323c-a77e-ee6498f52ecb 4 | PLATFORM_VERSION = 0.1 5 | DSC_SPECIFICATION = 0x00010005 6 | OUTPUT_DIRECTORY = LiorPkg 7 | SUPPORTED_ARCHITECTURES = X64 # IA32|IPF|X64|EBC 8 | BUILD_TARGETS = DEBUG # DEBUG|RELEASE 9 | 10 | [LibraryClasses] 11 | ## More library instances need to be added if more library classes are used 12 | ## by the components in the following [Components] section. 13 | ## library class name | library instance INF file path from package 14 | DebugLib | MdePkg/Library/UefiDebugLibStdErr/UefiDebugLibStdErr.inf 15 | BaseLib | MdePkg/Library/BaseLib/BaseLib.inf 16 | BaseMemoryLib | MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf 17 | 18 | ## Basic Library 19 | BaseLib|MdePkg/Library/BaseLib/BaseLib.inf 20 | DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf 21 | SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf 22 | CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf 23 | PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf 24 | PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf 25 | ## Pci Library 26 | PciCf8Lib|MdePkg/Library/BasePciCf8Lib/BasePciCf8Lib.inf 27 | PciExpressLib|MdePkg/Library/BasePciExpressLib/BasePciExpressLib.inf 28 | PciLib|MdePkg/Library/BasePciLibCf8/BasePciLibCf8.inf 29 | ## Entry Point Library 30 | PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf 31 | UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf 32 | UefiApplicationEntryPoint|MdePkg/Library/UefiApplicationEntryPoint/UefiApplicationEntryPoint.inf 33 | ## PEI service library 34 | PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf 35 | PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf 36 | ## UEFI and DXE service library 37 | UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf 38 | DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf 39 | UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf 40 | DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf 41 | UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf 42 | UefiLib|MdePkg/Library/UefiLib/UefiLib.inf 43 | DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf 44 | ## This library instance should be provide by chipset. 45 | TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf 46 | 47 | ## more stuff that prevented the package from compiling 48 | MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf 49 | RegisterFilterLib|MdePkg/Library/RegisterFilterLibNull/RegisterFilterLibNull.inf 50 | 51 | 52 | ##PCDs sections are not specified. 53 | ##All PCDs value are from their Default value in DEC. 54 | ##[PcdsFeatureFlag] 55 | ##[PcdsFixedAtBuild] 56 | [Components] 57 | # All libraries, drivers and applications are added here to be compiled 58 | # 59 | # Module INF file path are specified from package directory. 60 | LiorPkg/Lior/lior.inf 61 | -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | env: 10 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 11 | BUILD_TYPE: Release 12 | BUILD_TARGET: LiorPkg 13 | EDK2_REPO: https://github.com/tianocore/edk2.git 14 | EDK2_PATH: /tmp/edk2 15 | 16 | jobs: 17 | ###=================== 18 | # LINUX 19 | ###=================== 20 | 21 | # check that build succeed on linux systems 22 | build-linux: 23 | runs-on: ubuntu-22.04 24 | 25 | defaults: 26 | run: 27 | shell: bash 28 | 29 | steps: 30 | - uses: actions/checkout@v3 31 | 32 | # import edk2 and cache it, for faster runs 33 | - name: EDK2 cache 34 | id: cache-edk2 35 | uses: actions/cache@v3 36 | with: 37 | path: ${{env.EDK2_PATH}} 38 | key: edk2-repo 39 | # clone edk2 and it's submodules 40 | - name: Clone EDK2 41 | if: steps.cache-edk2.outputs.cache-hit != 'true' 42 | run: | 43 | git clone ${{env.EDK2_REPO}} ${{env.EDK2_PATH}} 44 | cd ${{env.EDK2_PATH}} 45 | git submodule update --init 46 | # make sure that edk2 in cache is up to date 47 | - name: Fetch EDK2 48 | if: steps.cache-edk2.outputs.cache-hit == 'true' 49 | run: | 50 | cd ${{env.EDK2_PATH}} 51 | git fetch 52 | git submodule update 53 | 54 | - name: Install dependencies 55 | run: sudo apt install build-essential uuid-dev iasl git nasm python-is-python3 56 | 57 | - name: Configure CMake 58 | # sets LOCAL_EDK2 to cached repo path, to make configuration faster 59 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DLOCAL_EDK2=${{env.EDK2_PATH}} 60 | 61 | - name: Build 62 | run: cmake --build ${{github.workspace}}/build --target ${{env.BUILD_TARGET}} 63 | 64 | - name: Save Artifacts 65 | uses: actions/upload-artifact@v3 66 | with: 67 | name: lior package binary 68 | path: ./**/OUTPUT/*.efi 69 | retention-days: 7 70 | 71 | 72 | ###=================== 73 | # MAC 74 | ###=================== 75 | 76 | # check that build succeed on mac systems 77 | build-mac: 78 | runs-on: macos-12 79 | 80 | defaults: 81 | run: 82 | shell: bash 83 | 84 | steps: 85 | - uses: actions/checkout@v3 86 | 87 | # import edk2 and cache it, for faster runs 88 | - name: EDK2 cache 89 | id: cache-edk2 90 | uses: actions/cache@v3 91 | with: 92 | path: ${{env.EDK2_PATH}} 93 | key: edk2-repo 94 | # clone edk2 and it's submodules 95 | - name: Clone EDK2 96 | if: steps.cache-edk2.outputs.cache-hit != 'true' 97 | run: | 98 | git clone ${{env.EDK2_REPO}} ${{env.EDK2_PATH}} 99 | cd ${{env.EDK2_PATH}} 100 | git submodule update --init 101 | # make sure that edk2 in cache is up to date 102 | - name: Fetch EDK2 103 | if: steps.cache-edk2.outputs.cache-hit == 'true' 104 | run: | 105 | cd ${{env.EDK2_PATH}} 106 | git fetch 107 | git submodule update 108 | 109 | - name: install dependencies 110 | run: | 111 | brew install mtoc nasm acpica qemu 112 | export PATH=/usr/local/bin:$PATH 113 | 114 | - name: Configure CMake 115 | # sets LOCAL_EDK2 to cached repo path, to make configuration faster 116 | # sets EDK2_TAG to `edk2-stable202111` because there is a problem with the latest stable of edk2 (2022 05) 117 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DLOCAL_EDK2=${{env.EDK2_PATH}} -DEDK2_TAG=edk2-stable202111 118 | 119 | - name: Build 120 | run: cmake --build ${{github.workspace}}/build --target ${{env.BUILD_TARGET}} 121 | 122 | - name: Save Artifacts 123 | uses: actions/upload-artifact@v3 124 | with: 125 | name: lior package binary 126 | path: ./**/OUTPUT/*.efi 127 | retention-days: 7 128 | 129 | 130 | ###=================== 131 | # WINDOWS 132 | ###=================== 133 | 134 | build-windows: 135 | runs-on: windows-2019 136 | 137 | defaults: 138 | run: 139 | shell: cmd 140 | 141 | env: 142 | EDK2_PATH: ${{github.workspace}}\\edk2 143 | 144 | steps: 145 | - uses: actions/checkout@v3 146 | 147 | # save nasm 148 | - name: cache nasm 149 | id: cache-nasm 150 | uses: actions/cache@v3 151 | with: 152 | path: C:\nasm 153 | key: nasm-path 154 | # edk2's setup scrip checks for nasm only at 'C:\nasm' so install it there 155 | - name: install nasm 156 | if: steps.cache-nasm.outputs.cache-hit != 'true' 157 | shell: powershell 158 | run: | 159 | md C:\nasm 160 | Invoke-WebRequest -Uri "https://www.nasm.us/pub/nasm/releasebuilds/2.15.05/win64/nasm-2.15.05-win64.zip" -OutFile "C:\nasm\nasm.zip" 161 | cd C:\nasm 162 | 7z e nasm.zip 163 | 164 | - name: Configure CMake 165 | # sets EDK2_TAG to `edk2-stable202108` because there is a problem with the latest stable of edk2 (2022 05) 166 | run: cmake -B ${{github.workspace}}\build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DEDK2_TAG=edk2-stable202108 167 | 168 | - name: Build 169 | run: | 170 | cmake --build ${{github.workspace}}\build --target ${{env.BUILD_TARGET}} 171 | 172 | - name: Save Artifacts 173 | uses: actions/upload-artifact@v3 174 | with: 175 | name: lior package binary 176 | path: ./**/OUTPUT/*.efi 177 | retention-days: 7 178 | 179 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EDK2 Project Template 2 | 3 | Making build for UEFI easy 4 | 5 |
6 | 7 | ## List of content 8 | 9 | - [Introduction](#introduction) 10 | - [Key Objectives](#key-objectives) 11 | - [Brief Overwiew](#brief-overwiew) 12 | - [Installing Dependencies](#installing-dependencies) 13 | - [Usage](#usage) 14 | - [Invoking Cmake via vscode](#invoking-cmake-via-vscode) 15 | - [Using Commandline](#using-commandline) 16 | - [Customizing via Cmake variables](#customizing-via-cmake-variables) 17 | - [Brief Description of edk2 build system](#brief-description-of-edk2-build-system) 18 | - [Creating your own Package](#creating-your-own-package) 19 | - [Intitialise the package](#intitialise-the-package) 20 | - [Create the Package folder](#create-the-package-folder) 21 | - [Create the Cmake file for the Package](#create-the-cmake-file-for-the-package) 22 | - [Configure the File](#configure-the-file) 23 | - [Create files for EDK2 build system](#create-files-for-edk2-build-system) 24 | - [use the automatic generation (not yet avaible)](#use-the-automatic-generation-not-yet-avaible) 25 | - [Create Platform file (.dsc)](#create-platform-file-dsc) 26 | - [Create Module file (.inf)](#create-module-file-inf) 27 | - [More Info on EDK2](#more-info-on-edk2) 28 | - [Lists of all tianocore documentation (more or less)](#lists-of-all-tianocore-documentation-more-or-less) 29 | - [Guides](#guides) 30 | - [Training](#training) 31 | - [Compilation Environment](#compilation-environment) 32 | - [Build Files specifications](#build-files-specifications) 33 | - [Security](#security) 34 | - [etc](#etc) 35 | - [Lot of info about computers](#lot-of-info-about-computers) 36 | - [COPYRIGHT](#copyright) 37 | 38 | ## Introduction 39 | 40 | ### Key Objectives 41 | 42 | - Quick and easy start of UEFI development for newbies 43 | - Easy out of EDK tree development 44 | - Zero hussle with EDK build setup 45 | 46 | ### Brief Overwiew 47 | 48 | This project is a cmake warper to edk's build system. 49 | And it is devided into 3 seperate components: 50 | 1. middleware scripts between cmake and edk's build command, located under `build_scripts`. 51 | 2. cmake files that implements the core of this build system, located under `cmake_files`. 52 | 3. packages for edk2, located under `uefi_apps`. 53 | 54 | ### Installing Dependencies 55 | 56 | This project does not has any dependencies by itself (except for Cmake and EDK2's existance obviously) 57 | 58 | You will need to intall the dependencies of EDK2. 59 | these links may be useful for installing these dependencies: 60 | 61 | - [mac](https://github.com/tianocore/tianocore.github.io/wiki/Xcode) 62 | - [windows](https://github.com/tianocore/tianocore.github.io/wiki/Windows-systems#compile-tools) 63 | - [linux](https://github.com/tianocore/tianocore.github.io/wiki/Using-EDK-II-with-Native-GCC) 64 | - [intro page](https://github.com/tianocore/tianocore.github.io/wiki/Getting-Started-with-EDK-II) 65 | 66 | ## Usage 67 | 68 | ### Invoking Cmake via vscode 69 | 70 | This is very straightforward, just use the gui to configure and build the project. 71 | For customizing the project you can add variables in the file `.vscode/settings.json`. 72 | 73 | ```json 74 | { 75 | "cmake.configureArgs" : [ 76 | "-D=", 77 | ] 78 | } 79 | ``` 80 | 81 | > ### Note 82 | > cmake may fail to configure or build when invoked from vs code. 83 | > if cmake fails, try to invoke it again from the commandline. 84 | 85 | ### Using Commandline 86 | 87 | Configure the project: 88 | 89 | ```sh 90 | cmake -S -B 91 | ``` 92 | 93 | Build the package: 94 | 95 | ```sh 96 | cmake --build --target 97 | ``` 98 | 99 | For customizing the project you can add variable via the flag `-D` when configuring the project: 100 | 101 | ```sh 102 | cmake -D= 103 | ``` 104 | 105 | ### Customizing via Cmake variables 106 | 107 | editing the following variables will change the build system behavior. 108 | 109 | | Variable | Type | Description | 110 | | --------------------- | ----------------- | -------------------------------------- | 111 | | LOCAL_EDK2 | URL or PATH | a local path or an url to edk2 repo | 112 | | EDK2_TAG | string | a tag name or commit or branch of edk2 | 113 | | VS_TAG | string | **WINDOWS_ONLY**
version of visual studio to use. Format: `VS` | 114 | | PYTHON_COMMAND | string | full path to python interperter or name of python command in path | 115 | | CORE_COUNT | int (as a string) | the amount of treads to use in the build process | 116 | | CONF_PATH | PATH | a path to save edk's build configuration | 117 | | | | | 118 | 119 | 120 | you may want to look at the source of the variables for deeper look. 121 | | Variable | definition/use Location | 122 | | ---------------------------------- | ----------------------------------- | 123 | | LOCAL_EDK2 | `cmake_files/generic/include_edk2.cmake` | 124 | | EDK2_TAG | `cmake_files/generic/include_edk2.cmake` | 125 | | VS_TAG | `cmake_files/windows/detect_visual_studio.cmake` | 126 | | PYTHON_COMMAND | `cmake_files/generic/detect_python.cmake` | 127 | | CORE_COUNT | `cmake_files/generic/core_count.cmake` | 128 | | CONF_PATH | `cmake_files/unix/configure_build_system.cmake` OR `` | 129 | | | `` | 130 | | | `` | 131 | 132 | 133 | ## Brief Description of edk2 build system 134 | 135 | The EDK project is composed of packages. 136 | Each package is independent or is dependent on other packages. 137 | Package is composed of several modules. Each module can depend on some other modules. 138 | 139 | Package is spcified by a `.dsc` file, which delares basic info like: 140 | 141 | - supported architectures 142 | - it's own modules 143 | - dependencies 144 | 145 | Module is specified by a `.inf` file, which declares more specific info like: 146 | 147 | - main function name (if have one) 148 | - it's source files 149 | - dependencies 150 | 151 | For more explanation, you may use the following links: 152 | 153 | - [setup](https://github.com/tianocore/tianocore.github.io/wiki/Getting-Started-with-EDK-II) 154 | - [build system](https://edk2-docs.gitbook.io/edk-ii-build-specification/4_edk_ii_build_process_overview/41_edk_ii_build_system) 155 | - [guide](https://edk2-docs.gitbook.io/edk-ii-module-writer-s-guide/2_an_edk_ii_package/21_introduction) 156 | 157 | ## Creating your own Package 158 | 159 | ### Initialize the package 160 | 161 | #### Create the Package folder 162 | 163 | Create new folder at `uefi_apps/Pkg` 164 | and make sure that the folder name format is `UpperCamelCase`. 165 | This is your "new" source root directory, 166 | add files and directories to this folder as the edk2 specification instructs. 167 | 168 | #### Create the Cmake file for the Package 169 | 170 | In the directory `uefi_apps` you need to create file named 171 | `_pkg.cmake`, in `snake_case`. 172 | Then add the following line at the bottom of the file `CMakeLists.txt`: 173 | 174 | ```cmake 175 | include(uefi_apps/_pkg.cmake) 176 | ``` 177 | 178 | ##### Configure the File 179 | 180 | 1. Declare on the package name, which must be equal to the name of the package's folder. 181 | i.e `set(PACKAGE_NAME )` 182 | 183 | 2. Create a list with the build arguments to edk's build command. 184 | you mast use the flag `--platform` in order to declare on the platform to compile. 185 | you can find more info on the arguments at [edk's website](https://edk2-docs.gitbook.io/edk-ii-basetools-user-guides/build). 186 | here is an example for build arguments: 187 | 188 | ```cmake 189 | set(BUILD_ARGS 190 | --arch=X64 # architecture to compile to 191 | --platform=/.dsc # the platform to compile 192 | -n 7 # amount of threads 193 | # the variable TOOL_CHAIN will be provided by the this build system 194 | --tagname=${TOOL_CHAIN} # tool chain to use, you don't have to mention this flag but it useful if edk's build system uses the wrong tool-chain for some reason 195 | ) 196 | ``` 197 | 198 | 3. use the function `add_package` to create a target for you package. 199 | the function recieves the package's name and then the build arguments, and creates a build target for you. 200 | you can simply write: `add_package(${PACKAGE_NAME} ${BUILD_ARGS})` 201 | 202 | here is an example for cmake file named `lior_pkg.cmake` that builds the package `LiorPkg`: 203 | 204 | ```cmake 205 | # the name of the package, this must be idendical to the name of the package dir 206 | set(PACKAGE_NAME LiorPkg) 207 | 208 | # build arguments for edk2 build system 209 | set(BUILD_ARGS 210 | --arch=X64 # architecture to compile to 211 | --platform=LiorPkg/lior.dsc # the platform to compile 212 | -n 7 # amount of threads 213 | --tagname=${TOOL_CHAIN} # tool chain to use 214 | ) 215 | # this would create a target for the package 216 | add_package(${PACKAGE_NAME} ${BUILD_ARGS}) 217 | ``` 218 | 219 | ### Create files for EDK2 build system 220 | 221 | #### Create Platform file (.dsc) 222 | 223 | The dsc file uses `ini` like syntax. 224 | 225 | > #### \[Defines\] Section 226 | > 227 | > This section defines importent information for edk2's build system. 228 | > The format for entries in this section is: ` = `. 229 | > You mast define these variables: 230 | > 231 | > | Variable name | Type | Description | 232 | > | ----------------------- | ------------------- | ----------- | 233 | > | DSC_SPECIFICATION | 32 bit hex or float | the version of the specification. It does not need to be changed, unless you use a specific feature that appears in a newer specification. Format: `.` or Upper 16 bits = Major, Lower 16 bit = Minor. | 234 | > | PLATFORM_NAME | String | a name for your platform, must be unique. | 235 | > | PLATFORM_GUID | uuid | an uuid for your platform, must be unique. | 236 | > | PLATFORM_VERSION | 32 bit hex or float | the version of your package. | 237 | > | OUTPUT_DIRECTORY | relative path | a path for placing your build artifacts, it's relative to `WORKSPACE` dir. | 238 | > | SUPPORTED_ARCHITECTURES | list | a list that contains all the architectures that the package supports. Format: `|`. | 239 | > | BUILD_TARGETS | list | list of your build targets. avaible options are `DEBUG` `RELEASE` `NOOPT`. To create more options you need to edit the file `tools_def.txt` in edk's build tools conf directory. | 240 | 241 | > #### \[LibraryClasses\] Section 242 | > 243 | > In this section you declare on the libraries your module is going to use. 244 | > Use the names declared here in `inf`'s file `[LibraryClasses]` section. 245 | > Format: `|[|...]` 246 | > **Note** you also need to declare on library classes needed by the modules you depend on. 247 | 248 | > #### \[Components\] Section 249 | > 250 | > Here you define the modules and libraries that will be compiled as part of the package. 251 | > Format: path to the `inf` file of the module: `/path/to/module.inf`. each path is seperated by a new line. 252 | 253 | > ### **Note** 254 | > 255 | > There are more section, these sctions are the basic sections that must be defined in order to compile the package. 256 | 257 | For more info, you may read the [dsc specification](https://edk2-docs.gitbook.io/edk-ii-dsc-specification). 258 | 259 | #### Create Module file (.inf) 260 | 261 | The inf file uses `ini` like syntax. 262 | 263 | > #### \[Definess\] Section 264 | > 265 | > This section defines importent information for edk2's build system. 266 | > The format for entries in this section is: ` = `. 267 | > You mast define these variables: 268 | > 269 | > | Variable name | Type | Description | 270 | > | ------------- | ------------------- | ----------- | 271 | > | INF_VERSION | 32 bit hex or float | the version of the specification, does not need to be changed, unless you use a specific feature that apears in newer specification. Format: `.` or Upper 16 bits = Major, Lower 16 bit = Minor. | 272 | > | BASE_NAME | string | an unique name for the module | 273 | > | FILE_GUID | uuid | an uuid for the module | 274 | > | MODULE_TYPE | string | the module's type i.e application or driver. For all module types, please see [module types table](https://edk2-docs.gitbook.io/edk-ii-inf-specification/appendix_f_module_types). | 275 | > | ENTRY_POINT | string | the name of the entry point function (only applies to applications and drivers) | 276 | 277 | > #### \[LibraryClasses\] Section 278 | > 279 | > In this section you declare on the libraies that your module is depended on. use the library names you have defined in the `inf` file. 280 | > each name sould be seperated by a new line. 281 | 282 | > #### \[Sources\] Section 283 | > 284 | > This section is used to declare on the source files of the module, both header files and source files must be declared here (and any other file that is part of the source). 285 | > This section contains the source file paths relative to `inf`'s file location. 286 | > Each path is seperated by a new line. 287 | 288 | > #### \[Packages\] Section 289 | > 290 | > This section is used to list all edk2's decleration files that are used by this module. 291 | > Sadly, I am not going to explain what decleraion files are, you only need to know that 292 | > **every** *executable* module need to declare on the file: `MdePkg/MdePkg.dec`. 293 | 294 | > ### **Note** 295 | > 296 | > There are more section, these sctions are the basic sections that must be defined in order to compile the module. 297 | 298 | For more info, you may read the [inf specification](https://edk2-docs.gitbook.io/edk-ii-inf-specification). 299 | 300 | ## More Info on EDK2 301 | 302 | ### Lists of all tianocore documentation (more or less) 303 | 304 | https://github.com/tianocore-docs/tianocore-docs.github.io 305 | https://github.com/tianocore/tianocore.github.io/wiki/EDK-II-Documents 306 | 307 | ### Guides 308 | 309 | https://edk2-docs.gitbook.io/edk-ii-module-writer-s-guide/ 310 | https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/ 311 | 312 | ### Training 313 | 314 | https://github.com/tianocore-training/Tianocore_Training_Contents/wiki 315 | https://github.com/tianocore/tianocore.github.io/wiki/Training 316 | https://github.com/tianocore-docs/Training 317 | 318 | ### Compilation Environment 319 | 320 | windows https://github.com/tianocore/tianocore.github.io/wiki/Windows-systems#compile-tools 321 | macos https://github.com/tianocore/tianocore.github.io/wiki/Xcode 322 | linux https://github.com/tianocore/tianocore.github.io/wiki/Using-EDK-II-with-Native-GCC 323 | https://edk2-docs.gitbook.io/edk-ii-basetools-user-guides/build 324 | https://edk2-docs.gitbook.io/edk-ii-build-specification/4_edk_ii_build_process_overview/41_edk_ii_build_system 325 | https://github.com/tianocore/tianocore.github.io/wiki/Getting-Started-with-EDK-II 326 | 327 | ### Build Files specifications 328 | 329 | https://edk2-docs.gitbook.io/edk-ii-fdf-specification/ 330 | https://edk2-docs.gitbook.io/edk-ii-dsc-specification 331 | https://edk2-docs.gitbook.io/edk-ii-dec-specification/ 332 | https://edk2-docs.gitbook.io/edk-ii-inf-specification 333 | 334 | ### Security 335 | 336 | https://edk2-docs.gitbook.io/a-tour-beyond-bios-memory-protection-in-uefi-bios/ 337 | https://edk2-docs.gitbook.io/security-advisory/ 338 | https://edk2-docs.gitbook.io/understanding-the-uefi-secure-boot-chain/ 339 | 340 | ### etc 341 | 342 | https://github.com/tianocore-docs 343 | https://edk2-docs.gitbook.io/edk-ii-c-coding-standards-specification/ 344 | 345 | ### Lot of info about computers 346 | 347 | https://opensecuritytraining.info/IntroBIOS.html 348 | 349 | ## COPYRIGHT 350 | Copyright (c) 2022 Lior Shalmay. All rights reserved. 351 | 352 | ## LICENSE 353 | This project is distributed both under Propriatary License and GPL-2 354 | -------------------------------------------------------------------------------- /LICENSE.GPL-2.0: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. -------------------------------------------------------------------------------- /scripts/cmake/detect_visual_studio.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os.path as path 3 | import pathlib 4 | import subprocess 5 | import sys 6 | from functools import reduce 7 | from io import StringIO 8 | from os import getenv 9 | from typing import Dict, List, TextIO, Tuple 10 | 11 | ### 12 | # defaults 13 | ### 14 | VS_INSTALLER_PATHS = [ 15 | path.join(getenv("ProgramFiles(x86)"), "Microsoft Visual Studio\\Installer\\vswhere.exe"), 16 | path.join(getenv("ProgramFiles"), "Microsoft Visual Studio\\Installer\\vswhere.exe"), 17 | ] 18 | VS_LOCATION_ENV_VARIABLES = [ 19 | ("VS140COMNTOOLS","VS2015"), 20 | ("VS120COMNTOOLS","VS2013"), 21 | ("VS110COMNTOOLS","VS2012"), 22 | ] 23 | 24 | ### 25 | # globals 26 | ### 27 | DEBUG = False 28 | OLD_VISUAL_STUDIO_DETECTED = False 29 | 30 | ### 31 | # constants 32 | ### 33 | VS_2022_MAJOR = 17 34 | ENV_SETUP_FILE_NAMES = [ 35 | "vcvars32.bat", 36 | "vsvars32.bat", 37 | "vcvars64.bat", 38 | "vsvars64.bat", 39 | "vcvarsall.bat", 40 | "vsvarsall.bat", 41 | ] 42 | ENV_SETUP_FILE_DIRS = [ 43 | "", 44 | "Common7\\Tools", 45 | "VC\\Auxiliary\\Build", 46 | ] 47 | ENV_SETUP_FILE_LOCATIONS = reduce(lambda x,y: x+y, 48 | [[path.join(dir,file_name) for file_name in ENV_SETUP_FILE_NAMES] 49 | for dir in ENV_SETUP_FILE_DIRS] 50 | ) 51 | ### 52 | # helper classes 53 | ### 54 | class VisualStudionNotFound(Exception): 55 | pass 56 | class ParseError(Exception): 57 | pass 58 | class VsWhereParseError(ParseError): 59 | pass 60 | # class VsWhereRunError(Exception): 61 | # pass 62 | class UnsupportedVersion(Exception): 63 | pass 64 | 65 | class VisualStudioInfo: 66 | """ 67 | parserse vswhere value pairs and convert them to a more usefull information 68 | """ 69 | # this table converts major VS version into an EDK2 toolchain tag. 70 | tag_lookup_table = { 71 | VS_2022_MAJOR: 'VS2019', # should be visual studio 2022, but it is not yet supported by EDK2 72 | 16: 'VS2019', 73 | 15: 'VS2017', 74 | 14: 'VS2015', 75 | 12: 'VS2013', 76 | 11: 'VS2012', 77 | } 78 | 79 | @staticmethod 80 | def parse_version(version: str) -> Tuple[int, int]: 81 | """converts version string into major and minor version. 82 | 83 | Args: 84 | version (str): dot seperated version string 85 | 86 | Raises: 87 | VsWhereParseError: if the version has an invalid format. 88 | 89 | Returns: 90 | Tuple(int, int): returns a pair of major and minor version. 91 | """ 92 | items = version.split('.') 93 | if len(items) < 2: 94 | raise VsWhereParseError('invalid version format') 95 | if not (items[0].isdecimal() or items[1].isdecimal()): 96 | raise VsWhereParseError('invalid version format') 97 | return int(items[0]), int(items[1]) 98 | 99 | @staticmethod 100 | def convert_major_to_tag(major_version: int) -> str: 101 | """_summary_ 102 | 103 | Args: 104 | major_version (int): _description_ 105 | 106 | Raises: 107 | UnsupportedVersion: _description_ 108 | 109 | Returns: 110 | str: _description_ 111 | """ 112 | # warn the user about using not yet supported version 113 | if VS_2022_MAJOR == major_version: 114 | print_error("WORNING: you visual studio version (2022) is not yet supported\r\n" + 115 | "\t using it as visual studio 2019" 116 | ) 117 | if major_version not in VisualStudioInfo.tag_lookup_table: 118 | raise UnsupportedVersion("you visual studio version is too old") 119 | return VisualStudioInfo.tag_lookup_table[major_version] 120 | 121 | def __init__(self, info_dict: Dict): 122 | """ 123 | Args: 124 | info_dict (Dict): the raw key value pair generated by VsWhere. 125 | """ 126 | self.id = info_dict['instanceId'] 127 | self.path = info_dict['installationPath'] 128 | self.version = info_dict['installationVersion'] 129 | self.raw_dict = info_dict 130 | self.major, self.minor = self.parse_version(self.version) 131 | self.vs_tag = self.convert_major_to_tag(self.major) 132 | 133 | def get(self, key: str) -> str: 134 | """searches for a key in the dict generated by VsWhere. 135 | 136 | Args: 137 | key (str): name of a field 138 | 139 | Returns: 140 | str: value of a field 141 | """ 142 | return self.raw_dict[key] 143 | 144 | ### 145 | # helper functions 146 | ### 147 | def print_error(*args,**kwargs): 148 | print(*args,file=sys.stderr,**kwargs) 149 | 150 | def debug_print(*args,**kwargs): 151 | """prints to stderr if the DEBUG global is True 152 | """ 153 | global DEBUG 154 | if DEBUG: 155 | print_error(*args,**kwargs) 156 | 157 | 158 | def parse_vswhere_output(output_file: TextIO) -> List[Dict]: 159 | """parsers VsWhere output in to a dict 160 | 161 | Note: 162 | returns array of pairs because if there are multiple versions of visual studio installed, 163 | vswhere will return information about each of them 164 | 165 | Args: 166 | output_file (TextIO): a file like object that contains VsWhere output 167 | 168 | Raises: 169 | VsWhereParseError: if unexpected output was found 170 | 171 | 172 | Returns: 173 | [dict]: array of value pairs 174 | """ 175 | result = [] 176 | 177 | ### 178 | # parse heading, make sure that we are on the right software 179 | ### 180 | line = output_file.readline() 181 | while line == "\r\n": 182 | line = output_file.readline() 183 | if line == "": 184 | # got empty string, reached end of file sooner than expected. 185 | raise VsWhereParseError("EOF was not expected") 186 | 187 | if not line.startswith("Visual Studio Locator"): 188 | raise VsWhereParseError("invalid format") 189 | 190 | line = output_file.readline().strip() 191 | if not line.startswith("Copyright"): 192 | raise VsWhereParseError("invalid format") 193 | 194 | line = output_file.readline() # should be empty line, ignore it 195 | 196 | ### 197 | # parse the data 198 | ### 199 | line = output_file.readline() 200 | if line == "": 201 | # got empty string, reached end of file sooner than expected. 202 | raise VsWhereParseError("EOF was not expected") 203 | line = line.strip() 204 | 205 | while True: 206 | current_data = {} 207 | while line != "": 208 | items = line.split(': ') 209 | # in some cases, there is an empty value 210 | if len(items) == 1: 211 | key = line.strip(':') 212 | value = None 213 | # expecting only key and value 214 | elif len(items) > 2: 215 | raise VsWhereParseError("invalid format") 216 | else: 217 | key = items[0].strip() 218 | value = items[1].strip() 219 | 220 | current_data[key] = value 221 | line = output_file.readline().strip() 222 | # end of loop 223 | if not current_data: 224 | # if the dict is empty, somthing went wrong in the parsing 225 | raise VsWhereParseError("invalid format") 226 | result.append(current_data) 227 | line = output_file.readline() 228 | if line == "": 229 | # reached EOF 230 | break 231 | line = line.strip() 232 | return result 233 | 234 | 235 | def get_infos_from_installer(vswhere_path: str) -> List[VisualStudioInfo]: 236 | """gets information from VS installer and parses it 237 | 238 | Args: 239 | vswhere_path (str): path to VsWhere 240 | 241 | Returns: 242 | [VisualStudioInfo]: list of information about all visual studios that have been found 243 | """ 244 | run_result = subprocess.run(vswhere_path, 245 | stdout=subprocess.PIPE, 246 | check=True, 247 | ) 248 | # get raw values 249 | stdout = StringIO(run_result.stdout.decode()) 250 | infos = parse_vswhere_output(stdout) 251 | result = [] 252 | for info in infos: 253 | try: 254 | # parse the values and add them to result 255 | result.append(VisualStudioInfo(info)) 256 | except UnsupportedVersion as e: 257 | global OLD_VISUAL_STUDIO_DETECTED 258 | OLD_VISUAL_STUDIO_DETECTED = True 259 | debug_print(e) 260 | return result 261 | 262 | 263 | def get_avaible_visual_studios_from_installers(vswhere_paths: List[str]) -> List[VisualStudioInfo]: 264 | """find information from all installlers 265 | 266 | Args: 267 | vswhere_paths (List): all paths to an vswhere executable 268 | 269 | Raises: 270 | VisualStudionNotFound: if did not find even s single visual studio 271 | 272 | Returns: 273 | [VisualStudioInfo]: list of all visual studio info that was found 274 | """ 275 | result = [] 276 | for installer in vswhere_paths: 277 | if path.exists(installer): 278 | try: 279 | result.extend(get_infos_from_installer(installer)) 280 | except (subprocess.CalledProcessError, VsWhereParseError) as e: 281 | debug_print(e) 282 | 283 | if not result: 284 | # make sure if we do not find any thing to raise an error about it 285 | raise VisualStudionNotFound("all installers does not have visual studio") 286 | return result 287 | 288 | def get_avaible_visual_studios_from_env() -> List[Tuple[str,str]]: 289 | """detects visual studio using env variables 290 | 291 | Raises: 292 | VisualStudionNotFound: if none of the expected env variables are defined. 293 | 294 | Returns: 295 | [(str,str)]: list of pairs, containing visual studio location and it's toolchain tag 296 | """ 297 | result = [] 298 | for env_var, tool_tag in VS_LOCATION_ENV_VARIABLES: 299 | vs_path = getenv(env_var) 300 | if vs_path != None: 301 | result.append((vs_path, tool_tag)) 302 | 303 | if not result: 304 | raise VisualStudionNotFound("None of visual studios env variables are defined") 305 | return result 306 | def parse_msbuild_output(output: str) -> str: 307 | """extracts visual studio's version string from msbuild output 308 | 309 | Args: 310 | output (str): msbuild's output 311 | 312 | Raises: 313 | ParseError: if the output is not msbuild 314 | 315 | Returns: 316 | str: visual studio version string 317 | """ 318 | # this line comes before the version string 319 | SIGNATURE_LINE = 'Microsoft (R) Build Engine version ' 320 | 321 | start_index = output.find(SIGNATURE_LINE) 322 | if start_index < 0: 323 | # cant find our signature 324 | raise ParseError("not msbuild output") 325 | start_index += len(SIGNATURE_LINE) 326 | # find the nearest new line, so we can isolate this line 327 | end_index = output.find('\n', start_index) 328 | # take the version string plus other literals 329 | tmp_string = output[start_index:end_index].strip() 330 | # get only the version string 331 | version_string = tmp_string.split(' ')[0] 332 | return version_string 333 | 334 | 335 | def get_vs_version(vsvars_script_path: str) -> Tuple[int,int]: 336 | """finds visual studio version based on vsvar*.bat script. 337 | 338 | Args: 339 | vsvars_script_path (str): full path to a vsvar*.bat file. 340 | 341 | Returns: 342 | (int,int): Major and Minor version of visual studio. 343 | """ 344 | # run the script (adds msbuild to PATH) then run msbuild to detect its version 345 | run_result = subprocess.run( 346 | ["cmd","/C",vsvars_script_path,'&&',"msbuild"], 347 | stdout=subprocess.PIPE, 348 | check=False, 349 | ) 350 | version_string = parse_msbuild_output(run_result.stdout.decode()) 351 | return VisualStudioInfo.parse_version(version_string) 352 | 353 | 354 | def find_vsvar_script(vs_dir: str) -> str: 355 | """finds vsvars script from known relative location to visual studio's dir 356 | 357 | Args: 358 | vs_dir (str): visual studio's install dir or tools dir 359 | 360 | Raises: 361 | FileNotFoundError: none vsvars script was found 362 | 363 | Returns: 364 | str: full path to vsvars script 365 | """ 366 | for relative_path in ENV_SETUP_FILE_LOCATIONS: 367 | full_path = path.join(vs_dir,relative_path) 368 | if path.exists(full_path): 369 | return full_path 370 | raise FileNotFoundError("could not find vsvar script") 371 | 372 | def get_argparse() -> argparse.ArgumentParser: 373 | parser = argparse.ArgumentParser( 374 | description="finds visual studio and returns its version + path to vsvar*.bat", 375 | ) 376 | parser.add_argument('--installer-paths', 377 | type=str, 378 | help="additional paths, seperated by colon, to search for visual studio installer", 379 | dest="installer_paths", 380 | default=None, 381 | ) 382 | parser.add_argument('--vs-tag', 383 | type=str, 384 | help="edk2 toolchain tag representing the desired visual studio version", 385 | dest='vs_tag', 386 | default=None, 387 | ) 388 | parser.add_argument('--vs-path', 389 | type=pathlib.Path, 390 | help="path to visual studio installation dir", 391 | dest='vs_path', 392 | default=None, 393 | ) 394 | parser.add_argument('--debug', 395 | action='store_true', 396 | help='enable debug prints', 397 | dest='debug' 398 | ) 399 | return parser 400 | 401 | ###======================== 402 | # main functions 403 | ###======================== 404 | def handle_additional_installers(command_line_arg: str): 405 | """handles the installer options 406 | and adds these installer into intelnal variable 407 | 408 | Args: 409 | command_line_arg (str): the value from the command line 410 | """ 411 | global VS_INSTALLER_PATHS 412 | for installer_path in command_line_arg.split(':'): 413 | if not path.exists(installer_path): 414 | print_error(f"ERROR: the provided installer path: {installer_path} DOES NOT EXISTS") 415 | exit(-1) 416 | if path.isdir(installer_path): 417 | installer_path = path.join(installer_path, 'vswhere.exe') 418 | if not path.exists(installer_path): 419 | print_error(f"ERROR: could not find 'vswhere.exe' in installer dir: '{installer_path}'") 420 | exit(-1) 421 | elif not installer_path.endswith('vswhere.exe'): 422 | print_error(f"ERROR: probided installer path does not ends with 'vswhere.exe': '{installer_path}'") 423 | exit(-1) 424 | VS_INSTALLER_PATHS.insert(0, installer_path) 425 | 426 | def handle_provided_visual_studio(vs_path: pathlib.Path, vs_tag: str = None): 427 | """handles the vs-path option 428 | 429 | Args: 430 | vs_path (pathlib.Path): the content of vs-path option 431 | vs_tag (str, optional): the option for vs-tag. Defaults to None. 432 | """ 433 | if not vs_path.exists(): 434 | print_error("ERROR: the provided visual studio path does not exists") 435 | exit(-1) 436 | 437 | if vs_path.is_file(): 438 | # it's not documented, but the program can recive direct path to vsvar/vcvar 439 | if not (vs_path.name.startswith("vsvar") or vs_path.name.startswith("vcvar")): 440 | print_error("ERROR: the provided visual studio path is not a directory") 441 | exit(-1) 442 | vsvar_path = str(vs_path) 443 | elif vs_path.is_dir(): 444 | vs_path = str(vs_path) 445 | try: 446 | vsvar_path = find_vsvar_script(vs_path) 447 | except FileNotFoundError as e: 448 | print_error("ERROR: "+str(e)) 449 | exit(-1) 450 | else: 451 | print_error("ERROR: the provided visual studio path does not exists") 452 | exit(-1) 453 | 454 | major,_ = get_vs_version(vsvar_path) 455 | version_tag = VisualStudioInfo.convert_major_to_tag(major) 456 | 457 | # make sure that the version that the user wants, matches the version of 458 | # visual studio that he has provided. 459 | if vs_tag: 460 | if vs_tag != version_tag: 461 | print_error(f"ERROR: the provided visual studio (ver: {version_tag}) does not much the provided version ({vs_tag})") 462 | exit(-1) 463 | print(",".join((vsvar_path, version_tag))) 464 | 465 | def main(): 466 | VISUAL_STUDIO_DETECTED = False # for error prints 467 | parser = get_argparse() 468 | args = parser.parse_args() 469 | if args.debug: 470 | # enable debug prints 471 | global DEBUG 472 | DEBUG = True 473 | 474 | if args.vs_tag: 475 | # make sure that we are reciving a valid tag 476 | if args.vs_tag not in VisualStudioInfo.tag_lookup_table.values(): 477 | print_error(f"ERROR: invalid visual studio version/tag: {args.vs_tag}") 478 | exit(-1) 479 | 480 | if args.installer_paths and args.vs_path: 481 | # conflicting argument 482 | print_error("ERROR: installers paths and visual studio path, cannot be given at the same time") 483 | exit(-1) 484 | 485 | if args.vs_path: 486 | handle_provided_visual_studio(args.vs_path, args.vs_tag) 487 | return 488 | 489 | elif args.installer_paths: 490 | handle_additional_installers(args.installer_paths) 491 | 492 | found_vs_info = None # will contain the first visual studio that was found 493 | 494 | try: 495 | vs_infos = get_avaible_visual_studios_from_installers(VS_INSTALLER_PATHS) 496 | # sort the visual studios, so the latest one is first 497 | vs_infos.sort(key=lambda i: i.major,reverse=True) 498 | 499 | for vs_info in vs_infos: 500 | VISUAL_STUDIO_DETECTED = True 501 | tag = vs_info.vs_tag 502 | try: 503 | vsvar_script = find_vsvar_script(vs_info.path) 504 | except FileNotFoundError as e: 505 | # if for some reason we can't find the script, don't fail, go to next one instead 506 | debug_print(e) 507 | continue 508 | 509 | if not args.vs_tag or vs_info.vs_tag == args.vs_tag: 510 | print(','.join((vsvar_script,tag))) 511 | return 512 | if not found_vs_info: 513 | found_vs_info = (vsvar_script, tag) 514 | except VisualStudionNotFound: 515 | debug_print("no visual studio was found from installers") 516 | 517 | debug_print("specified version was not found from installers") 518 | 519 | try: 520 | pairs = get_avaible_visual_studios_from_env() 521 | for vs_dir,tag in pairs: 522 | VISUAL_STUDIO_DETECTED = True 523 | try: 524 | vsvar_script = find_vsvar_script(vs_dir) 525 | except FileNotFoundError as e: 526 | debug_print(e) 527 | continue 528 | 529 | if not args.vs_tag or args.vs_tag == tag: 530 | print(','.join((vsvar_script,tag))) 531 | return 532 | if not found_vs_info: 533 | found_vs_info = (vsvar_script,tag) 534 | 535 | except VisualStudionNotFound: 536 | debug_print("no visual studio was found from env") 537 | 538 | # last resort 539 | if found_vs_info: 540 | print_error("WARNING: could not find the specified visual studio version, using lates found instead") 541 | print(','.join(found_vs_info)) 542 | return 543 | 544 | if VISUAL_STUDIO_DETECTED: 545 | print_error("ERROR: visual studio was detected, but could not find vsvar script") 546 | elif OLD_VISUAL_STUDIO_DETECTED: 547 | print_error("ERROR: old visual studio was detected, please install newer one") 548 | else: 549 | print_error("ERROR: could not find any visual studio, please provide one") 550 | exit(-1) 551 | 552 | 553 | if __name__ == '__main__': 554 | main() 555 | --------------------------------------------------------------------------------