12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572 |
- # SPDX-License-Identifier: Apache-2.0
- ########################################################
- # Table of contents
- ########################################################
- # 1. Zephyr-aware extensions
- # 1.1. zephyr_*
- # 1.2. zephyr_library_*
- # 1.2.1 zephyr_interface_library_*
- # 1.3. generate_inc_*
- # 1.4. board_*
- # 1.5. Misc.
- # 2. Kconfig-aware extensions
- # 2.1 Misc
- # 3. CMake-generic extensions
- # 3.1. *_ifdef
- # 3.2. *_ifndef
- # 3.3. *_option compiler compatibility checks
- # 3.3.1 Toolchain integration
- # 3.4. Debugging CMake
- # 3.5. File system management
- # 4. Devicetree extensions
- # 4.1 dt_*
- # 5. Zephyr linker functions
- # 5.1. zephyr_linker*
- ########################################################
- # 1. Zephyr-aware extensions
- ########################################################
- # 1.1. zephyr_*
- #
- # The following methods are for modifying the CMake library[0] called
- # "zephyr". zephyr is a catch-all CMake library for source files that
- # can be built purely with the include paths, defines, and other
- # compiler flags that all zephyr source files use.
- # [0] https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html
- #
- # Example usage:
- # zephyr_sources(
- # random_esp32.c
- # utils.c
- # )
- #
- # Is short for:
- # target_sources(zephyr PRIVATE
- # ${CMAKE_CURRENT_SOURCE_DIR}/random_esp32.c
- # ${CMAKE_CURRENT_SOURCE_DIR}/utils.c
- # )
- #
- # As a very high-level introduction here are two call graphs that are
- # purposely minimalistic and incomplete.
- #
- # zephyr_library_cc_option()
- # |
- # v
- # zephyr_library_compile_options() --> target_compile_options()
- #
- #
- # zephyr_cc_option() ---> target_cc_option()
- # |
- # v
- # zephyr_cc_option_fallback() ---> target_cc_option_fallback()
- # |
- # v
- # zephyr_compile_options() ---> target_compile_options()
- #
- # https://cmake.org/cmake/help/latest/command/target_sources.html
- function(zephyr_sources)
- foreach(arg ${ARGV})
- if(IS_DIRECTORY ${arg})
- message(FATAL_ERROR "zephyr_sources() was called on a directory")
- endif()
- target_sources(zephyr PRIVATE ${arg})
- endforeach()
- endfunction()
- # https://cmake.org/cmake/help/latest/command/target_include_directories.html
- function(zephyr_include_directories)
- foreach(arg ${ARGV})
- if(IS_ABSOLUTE ${arg})
- set(path ${arg})
- else()
- set(path ${CMAKE_CURRENT_SOURCE_DIR}/${arg})
- endif()
- target_include_directories(zephyr_interface INTERFACE ${path})
- endforeach()
- endfunction()
- # https://cmake.org/cmake/help/latest/command/target_include_directories.html
- function(zephyr_system_include_directories)
- foreach(arg ${ARGV})
- if(IS_ABSOLUTE ${arg})
- set(path ${arg})
- else()
- set(path ${CMAKE_CURRENT_SOURCE_DIR}/${arg})
- endif()
- target_include_directories(zephyr_interface SYSTEM INTERFACE ${path})
- endforeach()
- endfunction()
- # https://cmake.org/cmake/help/latest/command/target_compile_definitions.html
- function(zephyr_compile_definitions)
- target_compile_definitions(zephyr_interface INTERFACE ${ARGV})
- endfunction()
- # https://cmake.org/cmake/help/latest/command/target_compile_options.html
- function(zephyr_compile_options)
- target_compile_options(zephyr_interface INTERFACE ${ARGV})
- endfunction()
- # https://cmake.org/cmake/help/latest/command/target_link_libraries.html
- function(zephyr_link_libraries)
- target_link_libraries(zephyr_interface INTERFACE ${ARGV})
- endfunction()
- # See this file section 3.1. target_cc_option
- function(zephyr_cc_option)
- foreach(arg ${ARGV})
- target_cc_option(zephyr_interface INTERFACE ${arg})
- endforeach()
- endfunction()
- function(zephyr_cc_option_fallback option1 option2)
- target_cc_option_fallback(zephyr_interface INTERFACE ${option1} ${option2})
- endfunction()
- function(zephyr_ld_options)
- target_ld_options(zephyr_interface INTERFACE ${ARGV})
- endfunction()
- # Getter functions for extracting build information from
- # zephyr_interface. Returning lists, and strings is supported, as is
- # requesting specific categories of build information (defines,
- # includes, options).
- #
- # The naming convention follows:
- # zephyr_get_${build_information}_for_lang${format}(lang x [STRIP_PREFIX])
- # Where
- # the argument 'x' is written with the result
- # and
- # ${build_information} can be one of
- # - include_directories # -I directories
- # - system_include_directories # -isystem directories
- # - compile_definitions # -D'efines
- # - compile_options # misc. compiler flags
- # and
- # ${format} can be
- # - the empty string '', signifying that it should be returned as a list
- # - _as_string signifying that it should be returned as a string
- # and
- # ${lang} can be one of
- # - C
- # - CXX
- # - ASM
- #
- # STRIP_PREFIX
- #
- # By default the result will be returned ready to be passed directly
- # to a compiler, e.g. prefixed with -D, or -I, but it is possible to
- # omit this prefix by specifying 'STRIP_PREFIX' . This option has no
- # effect for 'compile_options'.
- #
- # e.g.
- # zephyr_get_include_directories_for_lang(ASM x)
- # writes "-Isome_dir;-Isome/other/dir" to x
- function(zephyr_get_include_directories_for_lang_as_string lang i)
- zephyr_get_include_directories_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN})
- convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
- set(${i} ${str_of_flags} PARENT_SCOPE)
- endfunction()
- function(zephyr_get_system_include_directories_for_lang_as_string lang i)
- zephyr_get_system_include_directories_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN})
- convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
- set(${i} ${str_of_flags} PARENT_SCOPE)
- endfunction()
- function(zephyr_get_compile_definitions_for_lang_as_string lang i)
- zephyr_get_compile_definitions_for_lang(${lang} list_of_flags DELIMITER " " ${ARGN})
- convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
- set(${i} ${str_of_flags} PARENT_SCOPE)
- endfunction()
- function(zephyr_get_compile_options_for_lang_as_string lang i)
- zephyr_get_compile_options_for_lang(${lang} list_of_flags DELIMITER " ")
- convert_list_of_flags_to_string_of_flags(list_of_flags str_of_flags)
- set(${i} ${str_of_flags} PARENT_SCOPE)
- endfunction()
- function(zephyr_get_include_directories_for_lang lang i)
- zephyr_get_parse_args(args ${ARGN})
- get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_INCLUDE_DIRECTORIES)
- process_flags(${lang} flags output_list)
- string(REPLACE ";" "$<SEMICOLON>" genexp_output_list "${output_list}")
- if(NOT ARGN)
- set(result_output_list "-I$<JOIN:${genexp_output_list},$<SEMICOLON>-I>")
- elseif(args_STRIP_PREFIX)
- # The list has no prefix, so don't add it.
- set(result_output_list ${output_list})
- elseif(args_DELIMITER)
- set(result_output_list "-I$<JOIN:${genexp_output_list},${args_DELIMITER}-I>")
- endif()
- set(${i} ${result_output_list} PARENT_SCOPE)
- endfunction()
- function(zephyr_get_system_include_directories_for_lang lang i)
- zephyr_get_parse_args(args ${ARGN})
- get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_SYSTEM_INCLUDE_DIRECTORIES)
- process_flags(${lang} flags output_list)
- string(REPLACE ";" "$<SEMICOLON>" genexp_output_list "${output_list}")
- set_ifndef(args_DELIMITER "$<SEMICOLON>")
- set(result_output_list "$<$<BOOL:${genexp_output_list}>:-isystem$<JOIN:${genexp_output_list},${args_DELIMITER}-isystem>>")
- set(${i} ${result_output_list} PARENT_SCOPE)
- endfunction()
- function(zephyr_get_compile_definitions_for_lang lang i)
- zephyr_get_parse_args(args ${ARGN})
- get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_DEFINITIONS)
- process_flags(${lang} flags output_list)
- string(REPLACE ";" "$<SEMICOLON>" genexp_output_list "${output_list}")
- set_ifndef(args_DELIMITER "$<SEMICOLON>")
- set(result_output_list "-D$<JOIN:${genexp_output_list},${args_DELIMITER}-D>")
- set(${i} ${result_output_list} PARENT_SCOPE)
- endfunction()
- function(zephyr_get_compile_options_for_lang lang i)
- zephyr_get_parse_args(args ${ARGN})
- get_property(flags TARGET zephyr_interface PROPERTY INTERFACE_COMPILE_OPTIONS)
- process_flags(${lang} flags output_list)
- string(REPLACE ";" "$<SEMICOLON>" genexp_output_list "${output_list}")
- set_ifndef(args_DELIMITER "$<SEMICOLON>")
- set(result_output_list "$<JOIN:${genexp_output_list},${args_DELIMITER}>")
- set(${i} ${result_output_list} PARENT_SCOPE)
- endfunction()
- # This function writes a dict to it's output parameter
- # 'return_dict'. The dict has information about the parsed arguments,
- #
- # Usage:
- # zephyr_get_parse_args(foo ${ARGN})
- # print(foo_STRIP_PREFIX) # foo_STRIP_PREFIX might be set to 1
- function(zephyr_get_parse_args return_dict)
- foreach(x ${ARGN})
- if(DEFINED single_argument)
- set(${single_argument} ${x} PARENT_SCOPE)
- unset(single_argument)
- else()
- if(x STREQUAL STRIP_PREFIX)
- set(${return_dict}_STRIP_PREFIX 1 PARENT_SCOPE)
- elseif(x STREQUAL NO_SPLIT)
- set(${return_dict}_NO_SPLIT 1 PARENT_SCOPE)
- elseif(x STREQUAL DELIMITER)
- set(single_argument ${return_dict}_DELIMITER)
- endif()
- endif()
- endforeach()
- endfunction()
- function(process_flags lang input output)
- # The flags might contains compile language generator expressions that
- # look like this:
- # $<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
- # $<$<COMPILE_LANGUAGE:CXX>:$<OTHER_EXPRESSION>>
- #
- # Flags that don't specify a language like this apply to all
- # languages.
- #
- # See COMPILE_LANGUAGE in
- # https://cmake.org/cmake/help/v3.3/manual/cmake-generator-expressions.7.html
- #
- # To deal with this, we apply a regex to extract the flag and also
- # to find out if the language matches.
- #
- # If this doesn't work out we might need to ban the use of
- # COMPILE_LANGUAGE and instead partition C, CXX, and ASM into
- # different libraries
- set(languages C CXX ASM)
- set(tmp_list "")
- foreach(flag ${${input}})
- set(is_compile_lang_generator_expression 0)
- foreach(l ${languages})
- if(flag MATCHES "<COMPILE_LANGUAGE:${l}>:([^>]+)>")
- set(updated_flag ${CMAKE_MATCH_1})
- set(is_compile_lang_generator_expression 1)
- if(${l} STREQUAL ${lang})
- # This test will match in case there are more generator expressions in the flag.
- # As example: $<$<COMPILE_LANGUAGE:C>:$<OTHER_EXPRESSION>>
- # $<$<OTHER_EXPRESSION:$<COMPILE_LANGUAGE:C>:something>>
- string(REGEX MATCH "(\\\$<)[^\\\$]*(\\\$<)[^\\\$]*(\\\$<)" IGNORE_RESULT ${flag})
- if(CMAKE_MATCH_2)
- # Nested generator expressions are used, just substitue `$<COMPILE_LANGUAGE:${l}>` to `1`
- string(REGEX REPLACE "\\\$<COMPILE_LANGUAGE:${l}>" "1" updated_flag ${flag})
- endif()
- list(APPEND tmp_list ${updated_flag})
- break()
- endif()
- endif()
- endforeach()
- if(NOT is_compile_lang_generator_expression)
- # SHELL is used to avoid de-deplucation, but when process flags
- # then this tag must be removed to return real compile/linker flags.
- if(flag MATCHES "SHELL:[ ]*(.*)")
- separate_arguments(flag UNIX_COMMAND ${CMAKE_MATCH_1})
- endif()
- # Flags may be placed inside generator expression, therefore any flag
- # which is not already a generator expression must have commas converted.
- if(NOT flag MATCHES "\\\$<.*>")
- string(REPLACE "," "$<COMMA>" flag "${flag}")
- endif()
- list(APPEND tmp_list ${flag})
- endif()
- endforeach()
- set(${output} ${tmp_list} PARENT_SCOPE)
- endfunction()
- function(convert_list_of_flags_to_string_of_flags ptr_list_of_flags string_of_flags)
- # Convert the list to a string so we can do string replace
- # operations on it and replace the ";" list separators with a
- # whitespace so the flags are spaced out
- string(REPLACE ";" " " locally_scoped_string_of_flags "${${ptr_list_of_flags}}")
- # Set the output variable in the parent scope
- set(${string_of_flags} ${locally_scoped_string_of_flags} PARENT_SCOPE)
- endfunction()
- macro(get_property_and_add_prefix result target property prefix)
- zephyr_get_parse_args(args ${ARGN})
- if(args_STRIP_PREFIX)
- set(maybe_prefix "")
- else()
- set(maybe_prefix ${prefix})
- endif()
- get_property(target_property TARGET ${target} PROPERTY ${property})
- foreach(x ${target_property})
- list(APPEND ${result} ${maybe_prefix}${x})
- endforeach()
- endmacro()
- # 1.2 zephyr_library_*
- #
- # Zephyr libraries use CMake's library concept and a set of
- # assumptions about how zephyr code is organized to cut down on
- # boilerplate code.
- #
- # A Zephyr library can be constructed by the function zephyr_library
- # or zephyr_library_named. The constructors create a CMake library
- # with a name accessible through the variable ZEPHYR_CURRENT_LIBRARY.
- #
- # The variable ZEPHYR_CURRENT_LIBRARY should seldom be needed since
- # the zephyr libraries have methods that modify the libraries. These
- # methods have the signature: zephyr_library_<target-function>
- #
- # The methods are wrappers around the CMake target_* functions. See
- # https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html for
- # documentation on the underlying target_* functions.
- #
- # The methods modify the CMake target_* API to reduce boilerplate;
- # PRIVATE is assumed
- # The target is assumed to be ZEPHYR_CURRENT_LIBRARY
- #
- # When a flag that is given through the zephyr_* API conflicts with
- # the zephyr_library_* API then precedence will be given to the
- # zephyr_library_* API. In other words, local configuration overrides
- # global configuration.
- # Constructor with a directory-inferred name
- macro(zephyr_library)
- zephyr_library_get_current_dir_lib_name(${ZEPHYR_BASE} lib_name)
- zephyr_library_named(${lib_name})
- endmacro()
- # Determines what the current directory's lib name would be according to the
- # provided base and writes it to the argument "lib_name"
- macro(zephyr_library_get_current_dir_lib_name base lib_name)
- # Remove the prefix (/home/sebo/zephyr/driver/serial/CMakeLists.txt => driver/serial/CMakeLists.txt)
- file(RELATIVE_PATH name ${base} ${CMAKE_CURRENT_LIST_FILE})
- # Remove the filename (driver/serial/CMakeLists.txt => driver/serial)
- get_filename_component(name ${name} DIRECTORY)
- # Replace / with __ (driver/serial => driver__serial)
- string(REGEX REPLACE "/" "__" name ${name})
- set(${lib_name} ${name})
- endmacro()
- # Constructor with an explicitly given name.
- macro(zephyr_library_named name)
- # This is a macro because we need add_library() to be executed
- # within the scope of the caller.
- set(ZEPHYR_CURRENT_LIBRARY ${name})
- add_library(${name} STATIC "")
- zephyr_append_cmake_library(${name})
- target_link_libraries(${name} PUBLIC zephyr_interface)
- endmacro()
- # Provides amend functionality to a Zephyr library for out-of-tree usage.
- #
- # When called from a Zephyr module, the corresponding zephyr library defined
- # within Zephyr will be looked up.
- #
- # Note, in order to ensure correct library when amending, the folder structure in the
- # Zephyr module must resemble the structure used in Zephyr, as example:
- #
- # Example: to amend the zephyr library created in
- # ZEPHYR_BASE/drivers/entropy/CMakeLists.txt
- # add the following file:
- # ZEPHYR_MODULE/drivers/entropy/CMakeLists.txt
- # with content:
- # zephyr_library_amend()
- # zephyr_libray_add_sources(...)
- #
- # It is also possible to use generator expression when amending to Zephyr
- # libraries.
- #
- # For example, in case it is required to expose the Zephyr library's folder as
- # include path then the following is possible:
- # zephyr_library_amend()
- # zephyr_library_include_directories($<TARGET_PROPERTY:SOURCE_DIR>)
- #
- # See the CMake documentation for more target properties or generator
- # expressions.
- #
- macro(zephyr_library_amend)
- # This is a macro because we need to ensure the ZEPHYR_CURRENT_LIBRARY and
- # following zephyr_library_* calls are executed within the scope of the
- # caller.
- if(NOT ZEPHYR_CURRENT_MODULE_DIR)
- message(FATAL_ERROR "Function only available for Zephyr modules.")
- endif()
- zephyr_library_get_current_dir_lib_name(${ZEPHYR_CURRENT_MODULE_DIR} lib_name)
- set(ZEPHYR_CURRENT_LIBRARY ${lib_name})
- endmacro()
- function(zephyr_link_interface interface)
- target_link_libraries(${interface} INTERFACE zephyr_interface)
- endfunction()
- #
- # zephyr_library versions of normal CMake target_<func> functions
- #
- function(zephyr_library_sources source)
- target_sources(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${source} ${ARGN})
- endfunction()
- function(zephyr_library_include_directories)
- target_include_directories(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${ARGN})
- endfunction()
- function(zephyr_library_link_libraries item)
- target_link_libraries(${ZEPHYR_CURRENT_LIBRARY} PUBLIC ${item} ${ARGN})
- endfunction()
- function(zephyr_library_compile_definitions item)
- target_compile_definitions(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${item} ${ARGN})
- endfunction()
- function(zephyr_library_compile_options item)
- # The compiler is relied upon for sane behaviour when flags are in
- # conflict. Compilers generally give precedence to flags given late
- # on the command line. So to ensure that zephyr_library_* flags are
- # placed late on the command line we create a dummy interface
- # library and link with it to obtain the flags.
- #
- # Linking with a dummy interface library will place flags later on
- # the command line than the the flags from zephyr_interface because
- # zephyr_interface will be the first interface library that flags
- # are taken from.
- string(MD5 uniqueness ${item})
- set(lib_name options_interface_lib_${uniqueness})
- if (TARGET ${lib_name})
- # ${item} already added, ignoring duplicate just like CMake does
- return()
- endif()
- add_library( ${lib_name} INTERFACE)
- target_compile_options(${lib_name} INTERFACE ${item} ${ARGN})
- target_link_libraries(${ZEPHYR_CURRENT_LIBRARY} PRIVATE ${lib_name})
- endfunction()
- function(zephyr_library_cc_option)
- foreach(option ${ARGV})
- string(MAKE_C_IDENTIFIER check${option} check)
- zephyr_check_compiler_flag(C ${option} ${check})
- if(${check})
- zephyr_library_compile_options(${option})
- endif()
- endforeach()
- endfunction()
- # Add the existing CMake library 'library' to the global list of
- # Zephyr CMake libraries. This is done automatically by the
- # constructor but must called explicitly on CMake libraries that do
- # not use a zephyr library constructor.
- function(zephyr_append_cmake_library library)
- if(TARGET zephyr_prebuilt)
- message(WARNING
- "zephyr_library() or zephyr_library_named() called in Zephyr CMake "
- "application mode. `${library}` will not be treated as a Zephyr library."
- "To create a Zephyr library in Zephyr CMake kernel mode consider "
- "creating a Zephyr module. See more here: "
- "https://docs.zephyrproject.org/latest/guides/modules.html"
- )
- endif()
- set_property(GLOBAL APPEND PROPERTY ZEPHYR_LIBS ${library})
- endfunction()
- # Add the imported library 'library_name', located at 'library_path' to the
- # global list of Zephyr CMake libraries.
- function(zephyr_library_import library_name library_path)
- add_library(${library_name} STATIC IMPORTED GLOBAL)
- set_target_properties(${library_name}
- PROPERTIES IMPORTED_LOCATION
- ${library_path}
- )
- zephyr_append_cmake_library(${library_name})
- endfunction()
- # Place the current zephyr library in the application memory partition.
- #
- # The partition argument is the name of the partition where the library shall
- # be placed.
- #
- # Note: Ensure the given partition has been define using
- # K_APPMEM_PARTITION_DEFINE in source code.
- function(zephyr_library_app_memory partition)
- set_property(TARGET zephyr_property_target
- APPEND PROPERTY COMPILE_OPTIONS
- "-l" $<TARGET_FILE_NAME:${ZEPHYR_CURRENT_LIBRARY}> "${partition}")
- endfunction()
- # Configure a Zephyr library specific property.
- #
- # Usage:
- # zephyr_library_property(<property> <value>)
- #
- # Current Zephyr library specific properties that are supported:
- # ALLOW_EMPTY <TRUE:FALSE>: Allow a Zephyr library to be empty.
- # An empty Zephyr library will generate a CMake
- # configure time warning unless `ALLOW_EMPTY` is TRUE.
- function(zephyr_library_property)
- set(single_args "ALLOW_EMPTY")
- cmake_parse_arguments(LIB_PROP "" "${single_args}" "" ${ARGN})
- if(LIB_PROP_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "zephyr_library_property(${ARGV0} ...) given unknown arguments: ${FILE_UNPARSED_ARGUMENTS}")
- endif()
- foreach(arg ${single_args})
- if(DEFINED LIB_PROP_${arg})
- set_property(TARGET ${ZEPHYR_CURRENT_LIBRARY} PROPERTY ${arg} ${LIB_PROP_${arg}})
- endif()
- endforeach()
- endfunction()
- # 1.2.1 zephyr_interface_library_*
- #
- # A Zephyr interface library is a thin wrapper over a CMake INTERFACE
- # library. The most important responsibility of this abstraction is to
- # ensure that when a user KConfig-enables a library then the header
- # files of this library will be accessible to the 'app' library.
- #
- # This is done because when a user uses Kconfig to enable a library he
- # expects to be able to include it's header files and call it's
- # functions out-of-the box.
- #
- # A Zephyr interface library should be used when there exists some
- # build information (include directories, defines, compiler flags,
- # etc.) that should be applied to a set of Zephyr libraries and 'app'
- # might be one of these libraries.
- #
- # Zephyr libraries must explicitly call
- # zephyr_library_link_libraries(<interface_library>) to use this build
- # information. 'app' is treated as a special case for usability
- # reasons; a Kconfig option (CONFIG_APP_LINK_WITH_<interface_library>)
- # should exist for each interface_library and will determine if 'app'
- # links with the interface_library.
- #
- # This API has a constructor like the zephyr_library API has, but it
- # does not have wrappers over the other cmake target functions.
- macro(zephyr_interface_library_named name)
- add_library(${name} INTERFACE)
- set_property(GLOBAL APPEND PROPERTY ZEPHYR_INTERFACE_LIBS ${name})
- endmacro()
- # 1.3 generate_inc_*
- # These functions are useful if there is a need to generate a file
- # that can be included into the application at build time. The file
- # can also be compressed automatically when embedding it.
- #
- # See tests/application_development/gen_inc_file for an example of
- # usage.
- function(generate_inc_file
- source_file # The source file to be converted to hex
- generated_file # The generated file
- )
- add_custom_command(
- OUTPUT ${generated_file}
- COMMAND
- ${PYTHON_EXECUTABLE}
- ${ZEPHYR_BASE}/scripts/file2hex.py
- ${ARGN} # Extra arguments are passed to file2hex.py
- --file ${source_file}
- > ${generated_file} # Does pipe redirection work on Windows?
- DEPENDS ${source_file}
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- )
- endfunction()
- function(generate_inc_file_for_gen_target
- target # The cmake target that depends on the generated file
- source_file # The source file to be converted to hex
- generated_file # The generated file
- gen_target # The generated file target we depend on
- # Any additional arguments are passed on to file2hex.py
- )
- generate_inc_file(${source_file} ${generated_file} ${ARGN})
- # Ensure 'generated_file' is generated before 'target' by creating a
- # dependency between the two targets
- add_dependencies(${target} ${gen_target})
- endfunction()
- function(generate_inc_file_for_target
- target # The cmake target that depends on the generated file
- source_file # The source file to be converted to hex
- generated_file # The generated file
- # Any additional arguments are passed on to file2hex.py
- )
- # Ensure 'generated_file' is generated before 'target' by creating a
- # 'custom_target' for it and setting up a dependency between the two
- # targets
- # But first create a unique name for the custom target
- generate_unique_target_name_from_filename(${generated_file} generated_target_name)
- add_custom_target(${generated_target_name} DEPENDS ${generated_file})
- generate_inc_file_for_gen_target(${target} ${source_file} ${generated_file} ${generated_target_name} ${ARGN})
- endfunction()
- # 1.4. board_*
- #
- # This section is for extensions related to Zephyr board handling.
- #
- # Zephyr board extensions current contains:
- # - Board runners
- # - Board revision
- # Zephyr board runners:
- # Zephyr board runner extension functions control Zephyr's board runners
- # from the build system. The Zephyr build system has targets for
- # flashing and debugging supported boards. These are wrappers around a
- # "runner" Python subpackage that is part of Zephyr's "west" tool.
- #
- # This section provides glue between CMake and the Python code that
- # manages the runners.
- function(_board_check_runner_type type) # private helper
- if (NOT (("${type}" STREQUAL "FLASH") OR ("${type}" STREQUAL "DEBUG")))
- message(FATAL_ERROR "invalid type ${type}; should be FLASH or DEBUG")
- endif()
- endfunction()
- # This function sets the runner for the board unconditionally. It's
- # meant to be used from application CMakeLists.txt files.
- #
- # NOTE: Usually board_set_xxx_ifnset() is best in board.cmake files.
- # This lets the user set the runner at cmake time, or in their
- # own application's CMakeLists.txt.
- #
- # Usage:
- # board_set_runner(FLASH pyocd)
- #
- # This would set the board's flash runner to "pyocd".
- #
- # In general, "type" is FLASH or DEBUG, and "runner" is the name of a
- # runner.
- function(board_set_runner type runner)
- _board_check_runner_type(${type})
- if (DEFINED BOARD_${type}_RUNNER)
- message(STATUS "overriding ${type} runner ${BOARD_${type}_RUNNER}; it's now ${runner}")
- endif()
- set(BOARD_${type}_RUNNER ${runner} PARENT_SCOPE)
- endfunction()
- # This macro is like board_set_runner(), but will only make a change
- # if that runner is currently not set.
- #
- # See also board_set_flasher_ifnset() and board_set_debugger_ifnset().
- macro(board_set_runner_ifnset type runner)
- _board_check_runner_type(${type})
- # This is a macro because set_ifndef() works at parent scope.
- # If this were a function, that would be this function's scope,
- # which wouldn't work.
- set_ifndef(BOARD_${type}_RUNNER ${runner})
- endmacro()
- # A convenience macro for board_set_runner(FLASH ${runner}).
- macro(board_set_flasher runner)
- board_set_runner(FLASH ${runner})
- endmacro()
- # A convenience macro for board_set_runner(DEBUG ${runner}).
- macro(board_set_debugger runner)
- board_set_runner(DEBUG ${runner})
- endmacro()
- # A convenience macro for board_set_runner_ifnset(FLASH ${runner}).
- macro(board_set_flasher_ifnset runner)
- board_set_runner_ifnset(FLASH ${runner})
- endmacro()
- # A convenience macro for board_set_runner_ifnset(DEBUG ${runner}).
- macro(board_set_debugger_ifnset runner)
- board_set_runner_ifnset(DEBUG ${runner})
- endmacro()
- # This function is intended for board.cmake files and application
- # CMakeLists.txt files.
- #
- # Usage from board.cmake files:
- # board_runner_args(runner "--some-arg=val1" "--another-arg=val2")
- #
- # The build system will then ensure the command line used to
- # create the runner contains:
- # --some-arg=val1 --another-arg=val2
- #
- # Within application CMakeLists.txt files, ensure that all calls to
- # board_runner_args() are part of a macro named app_set_runner_args(),
- # like this, which is defined before including the boilerplate file:
- # macro(app_set_runner_args)
- # board_runner_args(runner "--some-app-setting=value")
- # endmacro()
- #
- # The build system tests for the existence of the macro and will
- # invoke it at the appropriate time if it is defined.
- #
- # Any explicitly provided settings given by this function override
- # defaults provided by the build system.
- function(board_runner_args runner)
- string(MAKE_C_IDENTIFIER ${runner} runner_id)
- # Note the "_EXPLICIT_" here, and see below.
- set_property(GLOBAL APPEND PROPERTY BOARD_RUNNER_ARGS_EXPLICIT_${runner_id} ${ARGN})
- endfunction()
- # This function is intended for internal use by
- # boards/common/runner.board.cmake files.
- #
- # Basic usage:
- # board_finalize_runner_args(runner)
- #
- # This ensures the build system captures all arguments added in any
- # board_runner_args() calls, and otherwise finishes registering a
- # runner for use.
- #
- # Extended usage:
- # board_runner_args(runner "--some-arg=default-value")
- #
- # This provides common or default values for arguments. These are
- # placed before board_runner_args() calls, so they generally take
- # precedence, except for arguments which can be given multiple times
- # (use these with caution).
- function(board_finalize_runner_args runner)
- # If the application provided a macro to add additional runner
- # arguments, handle them.
- if(COMMAND app_set_runner_args)
- app_set_runner_args()
- endif()
- # Retrieve the list of explicitly set arguments.
- string(MAKE_C_IDENTIFIER ${runner} runner_id)
- get_property(explicit GLOBAL PROPERTY "BOARD_RUNNER_ARGS_EXPLICIT_${runner_id}")
- # Note no _EXPLICIT_ here. This property contains the final list.
- set_property(GLOBAL APPEND PROPERTY BOARD_RUNNER_ARGS_${runner_id}
- # Default arguments from the common runner file come first.
- ${ARGN}
- # Arguments explicitly given with board_runner_args() come
- # next, so they take precedence over the common runner file.
- ${explicit}
- # Arguments given via the CMake cache come last of all. Users
- # can provide variables in this way from the CMake command line.
- ${BOARD_RUNNER_ARGS_${runner_id}}
- )
- # Add the finalized runner to the global property list.
- set_property(GLOBAL APPEND PROPERTY ZEPHYR_RUNNERS ${runner})
- endfunction()
- # Zephyr board revision:
- #
- # This section provides a function for revision checking.
- # Usage:
- # board_check_revision(FORMAT <LETTER | MAJOR.MINOR.PATCH>
- # [EXACT]
- # [DEFAULT_REVISION <revision>]
- # [HIGHEST_REVISION <revision>]
- # )
- #
- # Zephyr board extension function.
- #
- # This function can be used in `boards/<board>/revision.cmake` to check a user
- # requested revision against available board revisions.
- #
- # The function will check the revision from `-DBOARD=<board>@<revision>` that
- # is provided by the user according to the arguments.
- # When `EXACT` is not specified, this function will set the Zephyr build system
- # variable `ACTIVE_BOARD_REVISION` with the selected revision.
- #
- # FORMAT <LETTER | MAJOR.MINOR.PATCH>: Specify the revision format.
- # LETTER: Revision format is a single letter from A - Z.
- # MAJOR.MINOR.PATCH: Revision format is three numbers, separated by `.`,
- # `x.y.z`. Trailing zeroes may be omitted on the
- # command line, which means:
- # 1.0.0 == 1.0 == 1
- #
- # EXACT: Revision is required to be an exact match. As example, available revisions are:
- # 0.1.0 and 0.3.0, and user provides 0.2.0, then an error is reported
- # when `EXACT` is given.
- # If `EXACT` is not provided, then closest lower revision will be selected
- # as the active revision, which in the example will be `0.1.0`.
- #
- # DEFAULT_REVISION: Provides a default revision to use when user has not selected
- # a revision number. If no default revision is provided then
- # user will be printed with an error if no revision is given
- # on the command line.
- #
- # HIGHEST_REVISION: Allows to specify highest valid revision for a board.
- # This can be used to ensure that a newer board cannot be used
- # with an older Zephyr. As example, if current board supports
- # revisions 0.x.0-0.99.99 and 1.0.0-1.99.99, and it is expected
- # that current board implementation will not work with board
- # revision 2.0.0, then HIGHEST_REVISION can be set to 1.99.99,
- # and user will be printed with an error if using
- # `<board>@2.0.0` or higher.
- # This field is not needed when `EXACT` is used.
- #
- # VALID_REVISIONS: A list of valid revisions for this board.
- # If this argument is not provided, then each Kconfig fragment
- # of the form ``<board>_<revision>.conf`` in the board folder
- # will be used as a valid revision for the board.
- #
- function(board_check_revision)
- set(options EXACT)
- set(single_args FORMAT DEFAULT_REVISION HIGHEST_REVISION)
- set(multi_args VALID_REVISIONS)
- cmake_parse_arguments(BOARD_REV "${options}" "${single_args}" "${multi_args}" ${ARGN})
- string(TOUPPER ${BOARD_REV_FORMAT} BOARD_REV_FORMAT)
- if(NOT DEFINED BOARD_REVISION)
- if(DEFINED BOARD_REV_DEFAULT_REVISION)
- set(BOARD_REVISION ${BOARD_REV_DEFAULT_REVISION})
- set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE)
- else()
- message(FATAL_ERROR "No board revision specified, Board: `${BOARD}` \
- requires a revision. Please use: `-DBOARD=${BOARD}@<revision>`")
- endif()
- endif()
- if(DEFINED BOARD_REV_HIGHEST_REVISION)
- if(((BOARD_REV_FORMAT STREQUAL LETTER) AND
- (BOARD_REVISION STRGREATER BOARD_REV_HIGHEST_REVISION)) OR
- ((BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$") AND
- (BOARD_REVISION VERSION_GREATER BOARD_REV_HIGHEST_REVISION))
- )
- message(FATAL_ERROR "Board revision `${BOARD_REVISION}` greater than \
- highest supported revision `${BOARD_REV_HIGHEST_REVISION}`. \
- Please specify a valid board revision.")
- endif()
- endif()
- if(BOARD_REV_FORMAT STREQUAL LETTER)
- set(revision_regex "([A-Z])")
- elseif(BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$")
- set(revision_regex "((0|[1-9][0-9]*)(\.[0-9]+)(\.[0-9]+))")
- # We allow loose <board>@<revision> typing on command line.
- # so append missing zeroes.
- if(BOARD_REVISION MATCHES "((0|[1-9][0-9]*)(\.[0-9]+)?(\.[0-9]+)?)")
- if(NOT CMAKE_MATCH_3)
- set(BOARD_REVISION ${BOARD_REVISION}.0)
- set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE)
- endif()
- if(NOT CMAKE_MATCH_4)
- set(BOARD_REVISION ${BOARD_REVISION}.0)
- set(BOARD_REVISION ${BOARD_REVISION} PARENT_SCOPE)
- endif()
- endif()
- else()
- message(FATAL_ERROR "Invalid format specified for \
- `board_check_revision(FORMAT <LETTER | MAJOR.MINOR.PATCH>)`")
- endif()
- if(NOT (BOARD_REVISION MATCHES "^${revision_regex}$"))
- message(FATAL_ERROR "Invalid revision format used for `${BOARD_REVISION}`. \
- Board `${BOARD}` uses revision format: ${BOARD_REV_FORMAT}.")
- endif()
- if(NOT DEFINED BOARD_REV_VALID_REVISIONS)
- file(GLOB revision_candidates LIST_DIRECTORIES false RELATIVE ${BOARD_DIR}
- ${BOARD_DIR}/${BOARD}_*.conf
- )
- string(REPLACE "." "_" underscore_revision_regex ${revision_regex})
- set(file_revision_regex "${BOARD}_${underscore_revision_regex}.conf")
- foreach(candidate ${revision_candidates})
- if(${candidate} MATCHES "${file_revision_regex}")
- string(REPLACE "_" "." FOUND_BOARD_REVISION ${CMAKE_MATCH_1})
- list(APPEND BOARD_REV_VALID_REVISIONS ${FOUND_BOARD_REVISION})
- endif()
- endforeach()
- endif()
- if(${BOARD_REVISION} IN_LIST BOARD_REV_VALID_REVISIONS)
- # Found exact match.
- return()
- endif()
- if(NOT BOARD_REV_EXACT)
- foreach(TEST_REVISION ${BOARD_REV_VALID_REVISIONS})
- if((BOARD_REV_FORMAT MATCHES "^MAJOR\.MINOR\.PATCH$") AND
- (${BOARD_REVISION} VERSION_GREATER_EQUAL ${TEST_REVISION}) AND
- (${TEST_REVISION} VERSION_GREATER_EQUAL "${ACTIVE_BOARD_REVISION}")
- )
- set(ACTIVE_BOARD_REVISION ${TEST_REVISION})
- elseif((BOARD_REV_FORMAT STREQUAL LETTER) AND
- (${BOARD_REVISION} STRGREATER ${TEST_REVISION}) AND
- (${TEST_REVISION} STRGREATER "${ACTIVE_BOARD_REVISION}")
- )
- set(ACTIVE_BOARD_REVISION ${TEST_REVISION})
- endif()
- endforeach()
- endif()
- if(BOARD_REV_EXACT OR NOT DEFINED ACTIVE_BOARD_REVISION)
- message(FATAL_ERROR "Board revision `${BOARD_REVISION}` for board \
- `${BOARD}` not found. Please specify a valid board revision.")
- endif()
- set(ACTIVE_BOARD_REVISION ${ACTIVE_BOARD_REVISION} PARENT_SCOPE)
- endfunction()
- # 1.5. Misc.
- # zephyr_check_compiler_flag is a part of Zephyr's toolchain
- # infrastructure. It should be used when testing toolchain
- # capabilities and it should normally be used in place of the
- # functions:
- #
- # check_compiler_flag
- # check_c_compiler_flag
- # check_cxx_compiler_flag
- #
- # See check_compiler_flag() for API documentation as it has the same
- # API.
- #
- # It is implemented as a wrapper on top of check_compiler_flag, which
- # again wraps the CMake-builtin's check_c_compiler_flag and
- # check_cxx_compiler_flag.
- #
- # It takes time to check for compatibility of flags against toolchains
- # so we cache the capability test results in USER_CACHE_DIR (This
- # caching comes in addition to the caching that CMake does in the
- # build folder's CMakeCache.txt)
- function(zephyr_check_compiler_flag lang option check)
- # Check if the option is covered by any hardcoded check before doing
- # an automated test.
- zephyr_check_compiler_flag_hardcoded(${lang} "${option}" check exists)
- if(exists)
- set(check ${check} PARENT_SCOPE)
- return()
- endif()
- # Locate the cache directory
- set_ifndef(
- ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR
- ${USER_CACHE_DIR}/ToolchainCapabilityDatabase
- )
- # The toolchain capability database/cache is maintained as a
- # directory of files. The filenames in the directory are keys, and
- # the file contents are the values in this key-value store.
- # We need to create a unique key wrt. testing the toolchain
- # capability. This key must include everything that can affect the
- # toolchain test.
- #
- # Also, to fit the key into a filename we calculate the MD5 sum of
- # the key.
- # The 'cacheformat' must be bumped if a bug in the caching mechanism
- # is detected and all old keys must be invalidated.
- set(cacheformat 3)
- set(key_string "")
- set(key_string "${key_string}${cacheformat}_")
- set(key_string "${key_string}${TOOLCHAIN_SIGNATURE}_")
- set(key_string "${key_string}${lang}_")
- set(key_string "${key_string}${option}_")
- set(key_string "${key_string}${CMAKE_REQUIRED_FLAGS}_")
- string(MD5 key ${key_string})
- # Check the cache
- set(key_path ${ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR}/${key})
- if(EXISTS ${key_path})
- file(READ
- ${key_path} # File to be read
- key_value # Output variable
- LIMIT 1 # Read at most 1 byte ('0' or '1')
- )
- set(${check} ${key_value} PARENT_SCOPE)
- return()
- endif()
- # Flags that start with -Wno-<warning> can not be tested by
- # check_compiler_flag, they will always pass, but -W<warning> can be
- # tested, so to test -Wno-<warning> flags we test -W<warning>
- # instead.
- if("${option}" MATCHES "-Wno-(.*)")
- set(possibly_translated_option -W${CMAKE_MATCH_1})
- else()
- set(possibly_translated_option ${option})
- endif()
- check_compiler_flag(${lang} "${possibly_translated_option}" inner_check)
- set(${check} ${inner_check} PARENT_SCOPE)
- # Populate the cache
- if(NOT (EXISTS ${key_path}))
- # This is racy. As often with race conditions, this one can easily be
- # made worse and demonstrated with a simple delay:
- # execute_process(COMMAND "sleep" "5")
- # Delete the cache, add the sleep above and run twister with a
- # large number of JOBS. Once it's done look at the log.txt file
- # below and you will see that concurrent cmake processes created the
- # same files multiple times.
- # While there are a number of reasons why this race seems both very
- # unlikely and harmless, let's play it safe anyway and write to a
- # private, temporary file first. All modern filesystems seem to
- # support at least one atomic rename API and cmake's file(RENAME
- # ...) officially leverages that.
- string(RANDOM LENGTH 8 tempsuffix)
- file(
- WRITE
- "${key_path}_tmp_${tempsuffix}"
- ${inner_check}
- )
- file(
- RENAME
- "${key_path}_tmp_${tempsuffix}" "${key_path}"
- )
- # Populate a metadata file (only intended for trouble shooting)
- # with information about the hash, the toolchain capability
- # result, and the toolchain test.
- file(
- APPEND
- ${ZEPHYR_TOOLCHAIN_CAPABILITY_CACHE_DIR}/log.txt
- "${inner_check} ${key} ${key_string}\n"
- )
- endif()
- endfunction()
- function(zephyr_check_compiler_flag_hardcoded lang option check exists)
- # Various flags that are not supported for CXX may not be testable
- # because they would produce a warning instead of an error during
- # the test. Exclude them by toolchain-specific blocklist.
- if((${lang} STREQUAL CXX) AND ("${option}" IN_LIST CXX_EXCLUDED_OPTIONS))
- set(check 0 PARENT_SCOPE)
- set(exists 1 PARENT_SCOPE)
- else()
- # There does not exist a hardcoded check for this option.
- set(exists 0 PARENT_SCOPE)
- endif()
- endfunction(zephyr_check_compiler_flag_hardcoded)
- # zephyr_linker_sources(<location> [SORT_KEY <sort_key>] <files>)
- #
- # <files> is one or more .ld formatted files whose contents will be
- # copied/included verbatim into the given <location> in the global linker.ld.
- # Preprocessor directives work inside <files>. Relative paths are resolved
- # relative to the calling file, like zephyr_sources().
- # <location> is one of
- # NOINIT Inside the noinit output section.
- # RWDATA Inside the data output section.
- # RODATA Inside the rodata output section.
- # ROM_START Inside the first output section of the image. This option is
- # currently only available on ARM Cortex-M, ARM Cortex-R,
- # x86, ARC, openisa_rv32m1, and RISC-V.
- # Note: On RISC-V the rom_start section will be after vector section.
- # RAM_SECTIONS Inside the RAMABLE_REGION GROUP, not initialized.
- # DATA_SECTIONS Inside the RAMABLE_REGION GROUP, initialized.
- # SECTIONS Near the end of the file. Don't use this when linking into
- # RAMABLE_REGION, use RAM_SECTIONS instead.
- # <sort_key> is an optional key to sort by inside of each location. The key must
- # be alphanumeric, and the keys are sorted alphabetically. If no key is
- # given, the key 'default' is used. Keys are case-sensitive.
- #
- # Use NOINIT, RWDATA, and RODATA unless they don't work for your use case.
- #
- # When placing into NOINIT, RWDATA, RODATA, ROM_START, the contents of the files
- # will be placed inside an output section, so assume the section definition is
- # already present, e.g.:
- # _mysection_start = .;
- # KEEP(*(.mysection));
- # _mysection_end = .;
- # _mysection_size = ABSOLUTE(_mysection_end - _mysection_start);
- #
- # When placing into SECTIONS, RAM_SECTIONS or DATA_SECTIONS, the files must
- # instead define their own output sections to achieve the same thing:
- # SECTION_PROLOGUE(.mysection,,)
- # {
- # _mysection_start = .;
- # KEEP(*(.mysection))
- # _mysection_end = .;
- # } GROUP_LINK_IN(ROMABLE_REGION)
- # _mysection_size = _mysection_end - _mysection_start;
- #
- # Note about the above examples: If the first example was used with RODATA, and
- # the second with SECTIONS, the two examples do the same thing from a user
- # perspective.
- #
- # Friendly reminder: Beware of the different ways the location counter ('.')
- # behaves inside vs. outside section definitions.
- function(zephyr_linker_sources location)
- # Set up the paths to the destination files. These files are #included inside
- # the global linker.ld.
- set(snippet_base "${__build_dir}/include/generated")
- set(sections_path "${snippet_base}/snippets-sections.ld")
- set(ram_sections_path "${snippet_base}/snippets-ram-sections.ld")
- set(data_sections_path "${snippet_base}/snippets-data-sections.ld")
- set(rom_start_path "${snippet_base}/snippets-rom-start.ld")
- set(noinit_path "${snippet_base}/snippets-noinit.ld")
- set(rwdata_path "${snippet_base}/snippets-rwdata.ld")
- set(rodata_path "${snippet_base}/snippets-rodata.ld")
- # Clear destination files if this is the first time the function is called.
- get_property(cleared GLOBAL PROPERTY snippet_files_cleared)
- if (NOT DEFINED cleared)
- file(WRITE ${sections_path} "")
- file(WRITE ${ram_sections_path} "")
- file(WRITE ${data_sections_path} "")
- file(WRITE ${rom_start_path} "")
- file(WRITE ${noinit_path} "")
- file(WRITE ${rwdata_path} "")
- file(WRITE ${rodata_path} "")
- set_property(GLOBAL PROPERTY snippet_files_cleared true)
- endif()
- # Choose destination file, based on the <location> argument.
- if ("${location}" STREQUAL "SECTIONS")
- set(snippet_path "${sections_path}")
- elseif("${location}" STREQUAL "RAM_SECTIONS")
- set(snippet_path "${ram_sections_path}")
- elseif("${location}" STREQUAL "DATA_SECTIONS")
- set(snippet_path "${data_sections_path}")
- elseif("${location}" STREQUAL "ROM_START")
- set(snippet_path "${rom_start_path}")
- elseif("${location}" STREQUAL "NOINIT")
- set(snippet_path "${noinit_path}")
- elseif("${location}" STREQUAL "RWDATA")
- set(snippet_path "${rwdata_path}")
- elseif("${location}" STREQUAL "RODATA")
- set(snippet_path "${rodata_path}")
- else()
- message(fatal_error "Must choose valid location for linker snippet.")
- endif()
- cmake_parse_arguments(L "" "SORT_KEY" "" ${ARGN})
- set(SORT_KEY default)
- if(DEFINED L_SORT_KEY)
- set(SORT_KEY ${L_SORT_KEY})
- endif()
- foreach(file IN ITEMS ${L_UNPARSED_ARGUMENTS})
- # Resolve path.
- if(IS_ABSOLUTE ${file})
- set(path ${file})
- else()
- set(path ${CMAKE_CURRENT_SOURCE_DIR}/${file})
- endif()
- if(IS_DIRECTORY ${path})
- message(FATAL_ERROR "zephyr_linker_sources() was called on a directory")
- endif()
- # Find the relative path to the linker file from the include folder.
- file(RELATIVE_PATH relpath ${ZEPHYR_BASE}/include ${path})
- # Create strings to be written into the file
- set (include_str "/* Sort key: \"${SORT_KEY}\" */#include \"${relpath}\"")
- # Add new line to existing lines, sort them, and write them back.
- file(STRINGS ${snippet_path} lines) # Get current lines (without newlines).
- list(APPEND lines ${include_str})
- list(SORT lines)
- string(REPLACE ";" "\n;" lines "${lines}") # Add newline to each line.
- file(WRITE ${snippet_path} ${lines} "\n")
- endforeach()
- endfunction(zephyr_linker_sources)
- # Helper function for CONFIG_CODE_DATA_RELOCATION
- # Call this function with 2 arguments file and then memory location
- function(zephyr_code_relocate file location)
- if(NOT IS_ABSOLUTE ${file})
- set(file ${CMAKE_CURRENT_SOURCE_DIR}/${file})
- endif()
- set_property(TARGET code_data_relocation_target
- APPEND PROPERTY COMPILE_DEFINITIONS
- "${location}:${file}")
- endfunction()
- # Usage:
- # check_dtc_flag("-Wtest" DTC_WARN_TEST)
- #
- # Writes 1 to the output variable 'ok' if
- # the flag is supported, otherwise writes 0.
- #
- # using
- function(check_dtc_flag flag ok)
- execute_process(
- COMMAND
- ${DTC} ${flag} -v
- ERROR_QUIET
- OUTPUT_QUIET
- RESULT_VARIABLE dtc_check_ret
- )
- if (dtc_check_ret EQUAL 0)
- set(${ok} 1 PARENT_SCOPE)
- else()
- set(${ok} 0 PARENT_SCOPE)
- endif()
- endfunction()
- # Function to round number to next power of two.
- #
- # Usage:
- # pow2round(<variable>)
- #
- # Example:
- # set(test 2)
- # pow2round(test)
- # # test is still 2
- #
- # set(test 5)
- # pow2round(test)
- # # test is now 8
- #
- # Arguments:
- # n = Variable containing the number to round
- function(pow2round n)
- math(EXPR x "${${n}} & (${${n}} - 1)")
- if(${x} EQUAL 0)
- return()
- endif()
- math(EXPR ${n} "${${n}} | (${${n}} >> 1)")
- math(EXPR ${n} "${${n}} | (${${n}} >> 2)")
- math(EXPR ${n} "${${n}} | (${${n}} >> 4)")
- math(EXPR ${n} "${${n}} | (${${n}} >> 8)")
- math(EXPR ${n} "${${n}} | (${${n}} >> 16)")
- math(EXPR ${n} "${${n}} | (${${n}} >> 32)")
- math(EXPR ${n} "${${n}} + 1")
- set(${n} ${${n}} PARENT_SCOPE)
- endfunction()
- ########################################################
- # 2. Kconfig-aware extensions
- ########################################################
- #
- # Kconfig is a configuration language developed for the Linux
- # kernel. The below functions integrate CMake with Kconfig.
- #
- # 2.1 Misc
- #
- # import_kconfig(<prefix> <kconfig_fragment> [<keys>])
- #
- # Parse a KConfig fragment (typically with extension .config) and
- # introduce all the symbols that are prefixed with 'prefix' into the
- # CMake namespace. List all created variable names in the 'keys'
- # output variable if present.
- function(import_kconfig prefix kconfig_fragment)
- # Parse the lines prefixed with 'prefix' in ${kconfig_fragment}
- file(
- STRINGS
- ${kconfig_fragment}
- DOT_CONFIG_LIST
- REGEX "^${prefix}"
- ENCODING "UTF-8"
- )
- foreach (CONFIG ${DOT_CONFIG_LIST})
- # CONFIG could look like: CONFIG_NET_BUF=y
- # Match the first part, the variable name
- string(REGEX MATCH "[^=]+" CONF_VARIABLE_NAME ${CONFIG})
- # Match the second part, variable value
- string(REGEX MATCH "=(.+$)" CONF_VARIABLE_VALUE ${CONFIG})
- # The variable name match we just did included the '=' symbol. To just get the
- # part on the RHS we use match group 1
- set(CONF_VARIABLE_VALUE ${CMAKE_MATCH_1})
- if("${CONF_VARIABLE_VALUE}" MATCHES "^\"(.*)\"$") # Is surrounded by quotes
- set(CONF_VARIABLE_VALUE ${CMAKE_MATCH_1})
- endif()
- set("${CONF_VARIABLE_NAME}" "${CONF_VARIABLE_VALUE}" PARENT_SCOPE)
- list(APPEND keys "${CONF_VARIABLE_NAME}")
- endforeach()
- foreach(outvar ${ARGN})
- set(${outvar} "${keys}" PARENT_SCOPE)
- endforeach()
- endfunction()
- ########################################################
- # 3. CMake-generic extensions
- ########################################################
- #
- # These functions extend the CMake API in a way that is not particular
- # to Zephyr. Primarily they work around limitations in the CMake
- # language to allow cleaner build scripts.
- # 3.1. *_ifdef
- #
- # Functions for conditionally executing CMake functions with oneliners
- # e.g.
- #
- # if(CONFIG_FFT)
- # zephyr_library_source(
- # fft_32.c
- # fft_utils.c
- # )
- # endif()
- #
- # Becomes
- #
- # zephyr_source_ifdef(
- # CONFIG_FFT
- # fft_32.c
- # fft_utils.c
- # )
- #
- # More Generally
- # "<function-name>_ifdef(CONDITION args)"
- # Becomes
- # """
- # if(CONDITION)
- # <function-name>(args)
- # endif()
- # """
- #
- # ifdef functions are added on an as-need basis. See
- # https://cmake.org/cmake/help/latest/manual/cmake-commands.7.html for
- # a list of available functions.
- function(add_subdirectory_ifdef feature_toggle source_dir)
- if(${${feature_toggle}})
- add_subdirectory(${source_dir} ${ARGN})
- endif()
- endfunction()
- function(target_sources_ifdef feature_toggle target scope item)
- if(${${feature_toggle}})
- target_sources(${target} ${scope} ${item} ${ARGN})
- endif()
- endfunction()
- function(target_compile_definitions_ifdef feature_toggle target scope item)
- if(${${feature_toggle}})
- target_compile_definitions(${target} ${scope} ${item} ${ARGN})
- endif()
- endfunction()
- function(target_include_directories_ifdef feature_toggle target scope item)
- if(${${feature_toggle}})
- target_include_directories(${target} ${scope} ${item} ${ARGN})
- endif()
- endfunction()
- function(target_link_libraries_ifdef feature_toggle target item)
- if(${${feature_toggle}})
- target_link_libraries(${target} ${item} ${ARGN})
- endif()
- endfunction()
- function(add_compile_option_ifdef feature_toggle option)
- if(${${feature_toggle}})
- add_compile_options(${option})
- endif()
- endfunction()
- function(target_compile_option_ifdef feature_toggle target scope option)
- if(${feature_toggle})
- target_compile_options(${target} ${scope} ${option})
- endif()
- endfunction()
- function(target_cc_option_ifdef feature_toggle target scope option)
- if(${feature_toggle})
- target_cc_option(${target} ${scope} ${option})
- endif()
- endfunction()
- function(zephyr_library_sources_ifdef feature_toggle source)
- if(${${feature_toggle}})
- zephyr_library_sources(${source} ${ARGN})
- endif()
- endfunction()
- function(zephyr_sources_ifdef feature_toggle)
- if(${${feature_toggle}})
- zephyr_sources(${ARGN})
- endif()
- endfunction()
- function(zephyr_cc_option_ifdef feature_toggle)
- if(${${feature_toggle}})
- zephyr_cc_option(${ARGN})
- endif()
- endfunction()
- function(zephyr_ld_option_ifdef feature_toggle)
- if(${${feature_toggle}})
- zephyr_ld_options(${ARGN})
- endif()
- endfunction()
- function(zephyr_link_libraries_ifdef feature_toggle)
- if(${${feature_toggle}})
- zephyr_link_libraries(${ARGN})
- endif()
- endfunction()
- function(zephyr_compile_options_ifdef feature_toggle)
- if(${${feature_toggle}})
- zephyr_compile_options(${ARGN})
- endif()
- endfunction()
- function(zephyr_compile_definitions_ifdef feature_toggle)
- if(${${feature_toggle}})
- zephyr_compile_definitions(${ARGN})
- endif()
- endfunction()
- function(zephyr_include_directories_ifdef feature_toggle)
- if(${${feature_toggle}})
- zephyr_include_directories(${ARGN})
- endif()
- endfunction()
- function(zephyr_library_compile_definitions_ifdef feature_toggle item)
- if(${${feature_toggle}})
- zephyr_library_compile_definitions(${item} ${ARGN})
- endif()
- endfunction()
- function(zephyr_library_include_directories_ifdef feature_toggle)
- if(${${feature_toggle}})
- zephyr_library_include_directories(${ARGN})
- endif()
- endfunction()
- function(zephyr_library_compile_options_ifdef feature_toggle item)
- if(${${feature_toggle}})
- zephyr_library_compile_options(${item} ${ARGN})
- endif()
- endfunction()
- function(zephyr_link_interface_ifdef feature_toggle interface)
- if(${${feature_toggle}})
- target_link_libraries(${interface} INTERFACE zephyr_interface)
- endif()
- endfunction()
- function(zephyr_library_link_libraries_ifdef feature_toggle item)
- if(${${feature_toggle}})
- zephyr_library_link_libraries(${item})
- endif()
- endfunction()
- function(zephyr_linker_sources_ifdef feature_toggle)
- if(${${feature_toggle}})
- zephyr_linker_sources(${ARGN})
- endif()
- endfunction()
- macro(list_append_ifdef feature_toggle list)
- if(${${feature_toggle}})
- list(APPEND ${list} ${ARGN})
- endif()
- endmacro()
- # 3.2. *_ifndef
- # See 3.1 *_ifdef
- function(set_ifndef variable value)
- if(NOT ${variable})
- set(${variable} ${value} ${ARGN} PARENT_SCOPE)
- endif()
- endfunction()
- function(add_subdirectory_ifndef feature_toggle source_dir)
- if(NOT ${feature_toggle})
- add_subdirectory(${source_dir} ${ARGN})
- endif()
- endfunction()
- function(target_sources_ifndef feature_toggle target scope item)
- if(NOT ${feature_toggle})
- target_sources(${target} ${scope} ${item} ${ARGN})
- endif()
- endfunction()
- function(target_compile_definitions_ifndef feature_toggle target scope item)
- if(NOT ${feature_toggle})
- target_compile_definitions(${target} ${scope} ${item} ${ARGN})
- endif()
- endfunction()
- function(target_include_directories_ifndef feature_toggle target scope item)
- if(NOT ${feature_toggle})
- target_include_directories(${target} ${scope} ${item} ${ARGN})
- endif()
- endfunction()
- function(target_link_libraries_ifndef feature_toggle target item)
- if(NOT ${feature_toggle})
- target_link_libraries(${target} ${item} ${ARGN})
- endif()
- endfunction()
- function(add_compile_option_ifndef feature_toggle option)
- if(NOT ${feature_toggle})
- add_compile_options(${option})
- endif()
- endfunction()
- function(target_compile_option_ifndef feature_toggle target scope option)
- if(NOT ${feature_toggle})
- target_compile_options(${target} ${scope} ${option})
- endif()
- endfunction()
- function(target_cc_option_ifndef feature_toggle target scope option)
- if(NOT ${feature_toggle})
- target_cc_option(${target} ${scope} ${option})
- endif()
- endfunction()
- function(zephyr_library_sources_ifndef feature_toggle source)
- if(NOT ${feature_toggle})
- zephyr_library_sources(${source} ${ARGN})
- endif()
- endfunction()
- function(zephyr_sources_ifndef feature_toggle)
- if(NOT ${feature_toggle})
- zephyr_sources(${ARGN})
- endif()
- endfunction()
- function(zephyr_cc_option_ifndef feature_toggle)
- if(NOT ${feature_toggle})
- zephyr_cc_option(${ARGN})
- endif()
- endfunction()
- function(zephyr_ld_option_ifndef feature_toggle)
- if(NOT ${feature_toggle})
- zephyr_ld_options(${ARGN})
- endif()
- endfunction()
- function(zephyr_link_libraries_ifndef feature_toggle)
- if(NOT ${feature_toggle})
- zephyr_link_libraries(${ARGN})
- endif()
- endfunction()
- function(zephyr_compile_options_ifndef feature_toggle)
- if(NOT ${feature_toggle})
- zephyr_compile_options(${ARGN})
- endif()
- endfunction()
- function(zephyr_compile_definitions_ifndef feature_toggle)
- if(NOT ${feature_toggle})
- zephyr_compile_definitions(${ARGN})
- endif()
- endfunction()
- function(zephyr_include_directories_ifndef feature_toggle)
- if(NOT ${feature_toggle})
- zephyr_include_directories(${ARGN})
- endif()
- endfunction()
- function(zephyr_library_compile_definitions_ifndef feature_toggle item)
- if(NOT ${feature_toggle})
- zephyr_library_compile_definitions(${item} ${ARGN})
- endif()
- endfunction()
- function(zephyr_library_include_directories_ifndef feature_toggle)
- if(NOT ${feature_toggle})
- zephyr_library_include_directories(${ARGN})
- endif()
- endfunction()
- function(zephyr_library_compile_options_ifndef feature_toggle item)
- if(NOT ${feature_toggle})
- zephyr_library_compile_options(${item} ${ARGN})
- endif()
- endfunction()
- function(zephyr_link_interface_ifndef feature_toggle interface)
- if(NOT ${feature_toggle})
- target_link_libraries(${interface} INTERFACE zephyr_interface)
- endif()
- endfunction()
- function(zephyr_library_link_libraries_ifndef feature_toggle item)
- if(NOT ${feature_toggle})
- zephyr_library_link_libraries(${item})
- endif()
- endfunction()
- function(zephyr_linker_sources_ifndef feature_toggle)
- if(NOT ${feature_toggle})
- zephyr_linker_sources(${ARGN})
- endif()
- endfunction()
- macro(list_append_ifndef feature_toggle list)
- if(NOT ${feature_toggle})
- list(APPEND ${list} ${ARGN})
- endif()
- endmacro()
- # 3.3. *_option Compiler-compatibility checks
- #
- # Utility functions for silently omitting compiler flags when the
- # compiler lacks support. *_cc_option was ported from KBuild, see
- # cc-option in
- # https://www.kernel.org/doc/Documentation/kbuild/makefiles.txt
- # Writes 1 to the output variable 'ok' for the language 'lang' if
- # the flag is supported, otherwise writes 0.
- #
- # lang must be C or CXX
- #
- # TODO: Support ASM
- #
- # Usage:
- #
- # check_compiler_flag(C "-Wall" my_check)
- # print(my_check) # my_check is now 1
- function(check_compiler_flag lang option ok)
- if(NOT DEFINED CMAKE_REQUIRED_QUIET)
- set(CMAKE_REQUIRED_QUIET 1)
- endif()
- string(MAKE_C_IDENTIFIER
- check${option}_${lang}_${CMAKE_REQUIRED_FLAGS}
- ${ok}
- )
- if(${lang} STREQUAL C)
- check_c_compiler_flag("${option}" ${${ok}})
- else()
- check_cxx_compiler_flag("${option}" ${${ok}})
- endif()
- if(${${${ok}}})
- set(ret 1)
- else()
- set(ret 0)
- endif()
- set(${ok} ${ret} PARENT_SCOPE)
- endfunction()
- function(target_cc_option target scope option)
- target_cc_option_fallback(${target} ${scope} ${option} "")
- endfunction()
- # Support an optional second option for when the first option is not
- # supported.
- function(target_cc_option_fallback target scope option1 option2)
- if(CONFIG_CPLUSPLUS)
- foreach(lang C CXX)
- # For now, we assume that all flags that apply to C/CXX also
- # apply to ASM.
- zephyr_check_compiler_flag(${lang} ${option1} check)
- if(${check})
- target_compile_options(${target} ${scope}
- $<$<COMPILE_LANGUAGE:${lang}>:${option1}>
- $<$<COMPILE_LANGUAGE:ASM>:${option1}>
- )
- elseif(option2)
- target_compile_options(${target} ${scope}
- $<$<COMPILE_LANGUAGE:${lang}>:${option2}>
- $<$<COMPILE_LANGUAGE:ASM>:${option2}>
- )
- endif()
- endforeach()
- else()
- zephyr_check_compiler_flag(C ${option1} check)
- if(${check})
- target_compile_options(${target} ${scope} ${option1})
- elseif(option2)
- target_compile_options(${target} ${scope} ${option2})
- endif()
- endif()
- endfunction()
- function(target_ld_options target scope)
- zephyr_get_parse_args(args ${ARGN})
- list(REMOVE_ITEM ARGN NO_SPLIT)
- foreach(option ${ARGN})
- if(args_NO_SPLIT)
- set(option ${ARGN})
- endif()
- string(JOIN "" check_identifier "check" ${option})
- string(MAKE_C_IDENTIFIER ${check_identifier} check)
- set(SAVED_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
- string(JOIN " " CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS} ${option})
- zephyr_check_compiler_flag(C "" ${check})
- set(CMAKE_REQUIRED_FLAGS ${SAVED_CMAKE_REQUIRED_FLAGS})
- target_link_libraries_ifdef(${check} ${target} ${scope} ${option})
- if(args_NO_SPLIT)
- break()
- endif()
- endforeach()
- endfunction()
- # 3.3.1 Toolchain integration
- #
- # 'toolchain_parse_make_rule' is a function that parses the output of
- # 'gcc -M'.
- #
- # The argument 'input_file' is in input parameter with the path to the
- # file with the dependency information.
- #
- # The argument 'include_files' is an output parameter with the result
- # of parsing the include files.
- function(toolchain_parse_make_rule input_file include_files)
- file(STRINGS ${input_file} input)
- # The file is formatted like this:
- # empty_file.o: misc/empty_file.c \
- # nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts \
- # nrf52840_qiaa.dtsi
- # The dep file will contain `\` for line continuation.
- # This results in `\;` which is then treated a the char `;` instead of
- # the element separator, so let's get the pure `;` back.
- string(REPLACE "\;" ";" input_as_list ${input})
- # Pop the first line and treat it specially
- list(POP_FRONT input_as_list first_input_line)
- string(FIND ${first_input_line} ": " index)
- math(EXPR j "${index} + 2")
- string(SUBSTRING ${first_input_line} ${j} -1 first_include_file)
- # Remove whitespace before and after filename and convert to CMake path.
- string(STRIP "${first_include_file}" first_include_file)
- file(TO_CMAKE_PATH "${first_include_file}" first_include_file)
- set(result "${first_include_file}")
- # Remove whitespace before and after filename and convert to CMake path.
- foreach(file ${input_as_list})
- string(STRIP "${file}" file)
- file(TO_CMAKE_PATH "${file}" file)
- list(APPEND result "${file}")
- endforeach()
- set(${include_files} ${result} PARENT_SCOPE)
- endfunction()
- # 'check_set_linker_property' is a function that check the provided linker
- # flag and only set the linker property if the check succeeds
- #
- # This function is similar in nature to the CMake set_property function, but
- # with the extension that it will check that the linker supports the flag before
- # setting the property.
- #
- # APPEND: Flag indicated that the property should be appended to the existing
- # value list for the property.
- # TARGET: Name of target on which to add the property (commonly: linker)
- # PROPERTY: Name of property with the value(s) following immediately after
- # property name
- function(check_set_linker_property)
- set(options APPEND)
- set(single_args TARGET)
- set(multi_args PROPERTY)
- cmake_parse_arguments(LINKER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN})
- if(LINKER_PROPERTY_APPEND)
- set(APPEND "APPEND")
- endif()
- list(GET LINKER_PROPERTY_PROPERTY 0 property)
- list(REMOVE_AT LINKER_PROPERTY_PROPERTY 0)
- set(option ${LINKER_PROPERTY_PROPERTY})
- string(MAKE_C_IDENTIFIER check${option} check)
- set(SAVED_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
- set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${option}")
- zephyr_check_compiler_flag(C "" ${check})
- set(CMAKE_REQUIRED_FLAGS ${SAVED_CMAKE_REQUIRED_FLAGS})
- if(${check})
- set_property(TARGET ${LINKER_PROPERTY_TARGET} ${APPEND} PROPERTY ${property} ${option})
- endif()
- endfunction()
- # 'set_compiler_property' is a function that sets the property for the C and
- # C++ property targets used for toolchain abstraction.
- #
- # This function is similar in nature to the CMake set_property function, but
- # with the extension that it will set the property on both the compile and
- # compiler-cpp targets.
- #
- # APPEND: Flag indicated that the property should be appended to the existing
- # value list for the property.
- # PROPERTY: Name of property with the value(s) following immediately after
- # property name
- function(set_compiler_property)
- set(options APPEND)
- set(multi_args PROPERTY)
- cmake_parse_arguments(COMPILER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN})
- if(COMPILER_PROPERTY_APPEND)
- set(APPEND "APPEND")
- set(APPEND-CPP "APPEND")
- endif()
- set_property(TARGET compiler ${APPEND} PROPERTY ${COMPILER_PROPERTY_PROPERTY})
- set_property(TARGET compiler-cpp ${APPEND} PROPERTY ${COMPILER_PROPERTY_PROPERTY})
- endfunction()
- # 'check_set_compiler_property' is a function that check the provided compiler
- # flag and only set the compiler or compiler-cpp property if the check succeeds
- #
- # This function is similar in nature to the CMake set_property function, but
- # with the extension that it will check that the compiler supports the flag
- # before setting the property on compiler or compiler-cpp targets.
- #
- # APPEND: Flag indicated that the property should be appended to the existing
- # value list for the property.
- # PROPERTY: Name of property with the value(s) following immediately after
- # property name
- function(check_set_compiler_property)
- set(options APPEND)
- set(multi_args PROPERTY)
- cmake_parse_arguments(COMPILER_PROPERTY "${options}" "${single_args}" "${multi_args}" ${ARGN})
- if(COMPILER_PROPERTY_APPEND)
- set(APPEND "APPEND")
- set(APPEND-CPP "APPEND")
- endif()
- list(GET COMPILER_PROPERTY_PROPERTY 0 property)
- list(REMOVE_AT COMPILER_PROPERTY_PROPERTY 0)
- foreach(option ${COMPILER_PROPERTY_PROPERTY})
- if(CONFIG_CPLUSPLUS)
- zephyr_check_compiler_flag(CXX ${option} check)
- if(${check})
- set_property(TARGET compiler-cpp ${APPEND-CPP} PROPERTY ${property} ${option})
- set(APPEND-CPP "APPEND")
- endif()
- endif()
- zephyr_check_compiler_flag(C ${option} check)
- if(${check})
- set_property(TARGET compiler ${APPEND} PROPERTY ${property} ${option})
- set(APPEND "APPEND")
- endif()
- endforeach()
- endfunction()
- # 3.4. Debugging CMake
- # Usage:
- # print(BOARD)
- #
- # will print: "BOARD: nrf52dk_nrf52832"
- function(print arg)
- message(STATUS "${arg}: ${${arg}}")
- endfunction()
- # Usage:
- # assert(ZEPHYR_TOOLCHAIN_VARIANT "ZEPHYR_TOOLCHAIN_VARIANT not set.")
- #
- # will cause a FATAL_ERROR and print an error message if the first
- # expression is false
- macro(assert test comment)
- if(NOT ${test})
- message(FATAL_ERROR "Assertion failed: ${comment}")
- endif()
- endmacro()
- # Usage:
- # assert_not(OBSOLETE_VAR "OBSOLETE_VAR has been removed; use NEW_VAR instead")
- #
- # will cause a FATAL_ERROR and print an error message if the first
- # expression is true
- macro(assert_not test comment)
- if(${test})
- message(FATAL_ERROR "Assertion failed: ${comment}")
- endif()
- endmacro()
- # Usage:
- # assert_exists(CMAKE_READELF)
- #
- # will cause a FATAL_ERROR if there is no file or directory behind the
- # variable
- macro(assert_exists var)
- if(NOT EXISTS ${${var}})
- message(FATAL_ERROR "No such file or directory: ${var}: '${${var}}'")
- endif()
- endmacro()
- # 3.5. File system management
- function(check_if_directory_is_writeable dir ok)
- execute_process(
- COMMAND
- ${PYTHON_EXECUTABLE}
- ${ZEPHYR_BASE}/scripts/dir_is_writeable.py
- ${dir}
- RESULT_VARIABLE ret
- )
- if("${ret}" STREQUAL "0")
- # The directory is write-able
- set(${ok} 1 PARENT_SCOPE)
- else()
- set(${ok} 0 PARENT_SCOPE)
- endif()
- endfunction()
- function(find_appropriate_cache_directory dir)
- set(env_suffix_LOCALAPPDATA .cache)
- if(CMAKE_HOST_APPLE)
- # On macOS, ~/Library/Caches is the preferred cache directory.
- set(env_suffix_HOME Library/Caches)
- else()
- set(env_suffix_HOME .cache)
- endif()
- # Determine which env vars should be checked
- if(CMAKE_HOST_APPLE)
- set(dirs HOME)
- elseif(CMAKE_HOST_WIN32)
- set(dirs LOCALAPPDATA)
- else()
- # Assume Linux when we did not detect 'mac' or 'win'
- #
- # On Linux, freedesktop.org recommends using $XDG_CACHE_HOME if
- # that is defined and defaulting to $HOME/.cache otherwise.
- set(dirs
- XDG_CACHE_HOME
- HOME
- )
- endif()
- foreach(env_var ${dirs})
- if(DEFINED ENV{${env_var}})
- set(env_dir $ENV{${env_var}})
- set(test_user_dir ${env_dir}/${env_suffix_${env_var}})
- check_if_directory_is_writeable(${test_user_dir} ok)
- if(${ok})
- # The directory is write-able
- set(user_dir ${test_user_dir})
- break()
- else()
- # The directory was not writeable, keep looking for a suitable
- # directory
- endif()
- endif()
- endforeach()
- # Populate local_dir with a suitable directory for caching
- # files. Prefer a directory outside of the git repository because it
- # is good practice to have clean git repositories.
- if(DEFINED user_dir)
- # Zephyr's cache files go in the "zephyr" subdirectory of the
- # user's cache directory.
- set(local_dir ${user_dir}/zephyr)
- else()
- set(local_dir ${ZEPHYR_BASE}/.cache)
- endif()
- set(${dir} ${local_dir} PARENT_SCOPE)
- endfunction()
- function(generate_unique_target_name_from_filename filename target_name)
- get_filename_component(basename ${filename} NAME)
- string(REPLACE "." "_" x ${basename})
- string(REPLACE "@" "_" x ${x})
- string(MD5 unique_chars ${filename})
- set(${target_name} gen_${x}_${unique_chars} PARENT_SCOPE)
- endfunction()
- # Usage:
- # zephyr_file(<mode> <arg> ...)
- #
- # Zephyr file function extension.
- # This function currently support the following <modes>
- #
- # APPLICATION_ROOT <path>: Check all paths in provided variable, and convert
- # those paths that are defined with `-D<path>=<val>`
- # to absolute path, relative from `APPLICATION_SOURCE_DIR`
- # Issue an error for any relative path not specified
- # by user with `-D<path>`
- #
- # CONF_FILES <path>: Find all configuration files in path and return them in a
- # list. Configuration files will be:
- # - DTS: Overlay files (.overlay)
- # - Kconfig: Config fragments (.conf)
- # The conf file search will return existing configuration
- # files for the current board.
- # CONF_FILES takes the following additional arguments:
- # BOARD <board>: Find configuration files for specified board.
- # BOARD_REVISION <revision>: Find configuration files for specified board
- # revision. Requires BOARD to be specified.
- #
- # If no board is given the current BOARD and
- # BOARD_REVISION will be used.
- #
- # DTS <list>: List to populate with DTS overlay files
- # KCONF <list>: List to populate with Kconfig fragment files
- # BUILD <type>: Build type to include for search.
- # For example:
- # BUILD debug, will look for <board>_debug.conf
- # and <board>_debug.overlay, instead of <board>.conf
- #
- # returns an updated list of absolute paths
- function(zephyr_file)
- set(file_options APPLICATION_ROOT CONF_FILES)
- if((ARGC EQUAL 0) OR (NOT (ARGV0 IN_LIST file_options)))
- message(FATAL_ERROR "No <mode> given to `zephyr_file(<mode> <args>...)` function,\n \
- Please provide one of following: APPLICATION_ROOT, CONF_FILES")
- endif()
- if(${ARGV0} STREQUAL APPLICATION_ROOT)
- set(single_args APPLICATION_ROOT)
- elseif(${ARGV0} STREQUAL CONF_FILES)
- set(single_args CONF_FILES BOARD BOARD_REVISION DTS KCONF BUILD)
- endif()
- cmake_parse_arguments(FILE "" "${single_args}" "" ${ARGN})
- if(FILE_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "zephyr_file(${ARGV0} <path> ...) given unknown arguments: ${FILE_UNPARSED_ARGUMENTS}")
- endif()
- if(FILE_APPLICATION_ROOT)
- # Note: user can do: `-D<var>=<relative-path>` and app can at same
- # time specify `list(APPEND <var> <abs-path>)`
- # Thus need to check and update only CACHED variables (-D<var>).
- set(CACHED_PATH $CACHE{${FILE_APPLICATION_ROOT}})
- foreach(path ${CACHED_PATH})
- # The cached variable is relative path, i.e. provided by `-D<var>` or
- # `set(<var> CACHE)`, so let's update current scope variable to absolute
- # path from `APPLICATION_SOURCE_DIR`.
- if(NOT IS_ABSOLUTE ${path})
- set(abs_path ${APPLICATION_SOURCE_DIR}/${path})
- list(FIND ${FILE_APPLICATION_ROOT} ${path} index)
- if(NOT ${index} LESS 0)
- list(REMOVE_AT ${FILE_APPLICATION_ROOT} ${index})
- list(INSERT ${FILE_APPLICATION_ROOT} ${index} ${abs_path})
- endif()
- endif()
- endforeach()
- # Now all cached relative paths has been updated.
- # Let's check if anyone uses relative path as scoped variable, and fail
- foreach(path ${${FILE_APPLICATION_ROOT}})
- if(NOT IS_ABSOLUTE ${path})
- message(FATAL_ERROR
- "Relative path encountered in scoped variable: ${FILE_APPLICATION_ROOT}, value=${path}\n \
- Please adjust any `set(${FILE_APPLICATION_ROOT} ${path})` or `list(APPEND ${FILE_APPLICATION_ROOT} ${path})`\n \
- to absolute path using `\${CMAKE_CURRENT_SOURCE_DIR}/${path}` or similar. \n \
- Relative paths are only allowed with `-D${ARGV1}=<path>`")
- endif()
- endforeach()
- # This updates the provided argument in parent scope (callers scope)
- set(${FILE_APPLICATION_ROOT} ${${FILE_APPLICATION_ROOT}} PARENT_SCOPE)
- endif()
- if(FILE_CONF_FILES)
- if(DEFINED FILE_BOARD_REVISION AND NOT FILE_BOARD)
- message(FATAL_ERROR
- "zephyr_file(${ARGV0} <path> BOARD_REVISION ${FILE_BOARD_REVISION} ...)"
- " given without BOARD argument, please specify BOARD"
- )
- endif()
- if(NOT DEFINED FILE_BOARD)
- # Defaulting to system wide settings when BOARD is not given as argument
- set(FILE_BOARD ${BOARD})
- if(DEFINED BOARD_REVISION)
- set(FILE_BOARD_REVISION ${BOARD_REVISION})
- endif()
- endif()
- set(FILENAMES ${FILE_BOARD})
- if(DEFINED FILE_BOARD_REVISION)
- string(REPLACE "." "_" revision_string ${FILE_BOARD_REVISION})
- list(APPEND FILENAMES "${FILE_BOARD}_${revision_string}")
- endif()
- if(FILE_DTS)
- foreach(filename ${FILENAMES})
- if(EXISTS ${FILE_CONF_FILES}/${filename}.overlay)
- list(APPEND ${FILE_DTS} ${FILE_CONF_FILES}/${filename}.overlay)
- endif()
- endforeach()
- # This updates the provided list in parent scope (callers scope)
- set(${FILE_DTS} ${${FILE_DTS}} PARENT_SCOPE)
- endif()
- if(FILE_KCONF)
- foreach(filename ${FILENAMES})
- if(FILE_BUILD)
- set(filename "${filename}_${FILE_BUILD}")
- endif()
- if(EXISTS ${FILE_CONF_FILES}/${filename}.conf)
- list(APPEND ${FILE_KCONF} ${FILE_CONF_FILES}/${filename}.conf)
- endif()
- endforeach()
- # This updates the provided list in parent scope (callers scope)
- set(${FILE_KCONF} ${${FILE_KCONF}} PARENT_SCOPE)
- endif()
- endif()
- endfunction()
- # Usage:
- # zephyr_string(<mode> <out-var> <input> ...)
- #
- # Zephyr string function extension.
- # This function extends the CMake string function by providing additional
- # manipulation arguments to CMake string.
- #
- # SANITIZE: Ensure that the output string does not contain any special
- # characters. Special characters, such as -, +, =, $, etc. are
- # converted to underscores '_'.
- #
- # SANITIZE TOUPPER: Ensure that the output string does not contain any special
- # characters. Special characters, such as -, +, =, $, etc. are
- # converted to underscores '_'.
- # The sanitized string will be returned in UPPER case.
- #
- # returns the updated string
- function(zephyr_string)
- set(options SANITIZE TOUPPER)
- cmake_parse_arguments(ZEPHYR_STRING "${options}" "" "" ${ARGN})
- if (NOT ZEPHYR_STRING_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "Function zephyr_string() called without a return variable")
- endif()
- list(GET ZEPHYR_STRING_UNPARSED_ARGUMENTS 0 return_arg)
- list(REMOVE_AT ZEPHYR_STRING_UNPARSED_ARGUMENTS 0)
- list(JOIN ZEPHYR_STRING_UNPARSED_ARGUMENTS "" work_string)
- if(ZEPHYR_STRING_SANITIZE)
- string(REGEX REPLACE "[^a-zA-Z0-9_]" "_" work_string ${work_string})
- endif()
- if(ZEPHYR_STRING_TOUPPER)
- string(TOUPPER ${work_string} work_string)
- endif()
- set(${return_arg} ${work_string} PARENT_SCOPE)
- endfunction()
- # Usage:
- # zephyr_check_cache(<variable> [REQUIRED])
- #
- # Check the current CMake cache for <variable> and warn the user if the value
- # is being modified.
- #
- # This can be used to ensure the user does not accidentally try to change
- # Zephyr build variables, such as:
- # - BOARD
- # - SHIELD
- #
- # variable: Name of <variable> to check and set, for example BOARD.
- # REQUIRED: Optional flag. If specified, then an unset <variable> will be
- # treated as an error.
- # WATCH: Optional flag. If specified, watch the variable and print a warning if
- # the variable is later being changed.
- #
- # Details:
- # <variable> can be set by 3 sources.
- # - Using CMake argument, -D<variable>
- # - Using an environment variable
- # - In the project CMakeLists.txt before `find_package(Zephyr)`.
- #
- # CLI has the highest precedence, then comes environment variables,
- # and then finally CMakeLists.txt.
- #
- # The value defined on the first CMake invocation will be stored in the CMake
- # cache as CACHED_<variable>. This allows the Zephyr build system to detect
- # when a user reconfigures a sticky variable.
- #
- # A user can ignore all the precedence rules if the same source is always used
- # E.g. always specifies -D<variable>= on the command line,
- # always has an environment <variable> set, or always has a set(<variable> foo)
- # line in his CMakeLists.txt and avoids mixing sources.
- #
- # The selected <variable> can be accessed through the variable '<variable>' in
- # following Zephyr CMake code.
- #
- # If the user tries to change <variable> to a new value, then a warning will
- # be printed, and the previously cached value (CACHED_<variable>) will be
- # used, as it has precedence.
- #
- # Together with the warning, user is informed that in order to change
- # <variable> the build directory must be cleaned.
- #
- function(zephyr_check_cache variable)
- cmake_parse_arguments(CACHE_VAR "REQUIRED;WATCH" "" "" ${ARGN})
- string(TOLOWER ${variable} variable_text)
- string(REPLACE "_" " " variable_text ${variable_text})
- get_property(cached_value CACHE ${variable} PROPERTY VALUE)
- # If the build has already been configured in an earlier CMake invocation,
- # then CACHED_${variable} is set. The CACHED_${variable} setting takes
- # precedence over any user or CMakeLists.txt input.
- # If we detect that user tries to change the setting, then print a warning
- # that a pristine build is needed.
- # If user uses -D<variable>=<new_value>, then cli_argument will hold the new
- # value, otherwise cli_argument will hold the existing (old) value.
- set(cli_argument ${cached_value})
- if(cli_argument STREQUAL CACHED_${variable})
- # The is no changes to the <variable> value.
- unset(cli_argument)
- endif()
- set(app_cmake_lists ${${variable}})
- if(cached_value STREQUAL ${variable})
- # The app build scripts did not set a default, The BOARD we are
- # reading is the cached value from the CLI
- unset(app_cmake_lists)
- endif()
- if(DEFINED CACHED_${variable})
- # Warn the user if it looks like he is trying to change the board
- # without cleaning first
- if(cli_argument)
- if(NOT ((CACHED_${variable} STREQUAL cli_argument) OR (${variable}_DEPRECATED STREQUAL cli_argument)))
- message(WARNING "The build directory must be cleaned pristinely when "
- "changing ${variable_text},\n"
- "Current value=\"${CACHED_${variable}}\", "
- "Ignored value=\"${cli_argument}\"")
- endif()
- endif()
- if(CACHED_${variable})
- set(${variable} ${CACHED_${variable}} PARENT_SCOPE)
- # This resets the user provided value with previous (working) value.
- set(${variable} ${CACHED_${variable}} CACHE STRING "Selected ${variable_text}" FORCE)
- else()
- unset(${variable} PARENT_SCOPE)
- unset(${variable} CACHE)
- endif()
- elseif(cli_argument)
- set(${variable} ${cli_argument})
- elseif(DEFINED ENV{${variable}})
- set(${variable} $ENV{${variable}})
- elseif(app_cmake_lists)
- set(${variable} ${app_cmake_lists})
- elseif(${CACHE_VAR_REQUIRED})
- message(FATAL_ERROR "${variable} is not being defined on the CMake command-line in the environment or by the app.")
- endif()
- # Store the specified variable in parent scope and the cache
- set(${variable} ${${variable}} PARENT_SCOPE)
- set(CACHED_${variable} ${${variable}} CACHE STRING "Selected ${variable_text}")
- if(CACHE_VAR_WATCH)
- # The variable is now set to its final value.
- zephyr_boilerplate_watch(${variable})
- endif()
- endfunction(zephyr_check_cache variable)
- # Usage:
- # zephyr_boilerplate_watch(SOME_BOILERPLATE_VAR)
- #
- # Inform the build system that SOME_BOILERPLATE_VAR, a variable
- # handled in cmake/app/boilerplate.cmake, is now fixed and should no
- # longer be changed.
- #
- # This function uses variable_watch() to print a noisy warning
- # if the variable is set after it returns.
- function(zephyr_boilerplate_watch variable)
- variable_watch(${variable} zephyr_variable_set_too_late)
- endfunction()
- function(zephyr_variable_set_too_late variable access value current_list_file)
- if (access STREQUAL "MODIFIED_ACCESS")
- message(WARNING
- "
- **********************************************************************
- *
- * WARNING
- *
- * CMake variable ${variable} set to \"${value}\" in:
- * ${current_list_file}
- *
- * This is too late to make changes! The change was ignored.
- *
- * Hint: ${variable} must be set before calling find_package(Zephyr ...).
- *
- **********************************************************************
- ")
- endif()
- endfunction()
- # Usage:
- # zephyr_get_targets(<directory> <types> <targets>)
- #
- # Get build targets for a given directory and sub-directories.
- #
- # This functions will traverse the build tree, starting from <directory>.
- # It will read the `BUILDSYSTEM_TARGETS` for each directory in the build tree
- # and return the build types matching the <types> list.
- # Example of types: OBJECT_LIBRARY, STATIC_LIBRARY, INTERFACE_LIBRARY, UTILITY.
- #
- # returns a list of targets in <targets> matching the required <types>.
- function(zephyr_get_targets directory types targets)
- get_property(sub_directories DIRECTORY ${directory} PROPERTY SUBDIRECTORIES)
- get_property(dir_targets DIRECTORY ${directory} PROPERTY BUILDSYSTEM_TARGETS)
- foreach(dir_target ${dir_targets})
- get_property(target_type TARGET ${dir_target} PROPERTY TYPE)
- if(${target_type} IN_LIST types)
- list(APPEND ${targets} ${dir_target})
- endif()
- endforeach()
- foreach(directory ${sub_directories})
- zephyr_get_targets(${directory} "${types}" ${targets})
- endforeach()
- set(${targets} ${${targets}} PARENT_SCOPE)
- endfunction()
- # Usage:
- # target_byproducts(TARGET <target> BYPRODUCTS <file> [<file>...])
- #
- # Specify additional BYPRODUCTS that this target produces.
- #
- # This function allows the build system to specify additional byproducts to
- # target created with `add_executable()`. When linking an executable the linker
- # may produce additional files, like map files. Those files are not known to the
- # build system. This function makes it possible to describe such additional
- # byproducts in an easy manner.
- function(target_byproducts)
- cmake_parse_arguments(TB "" "TARGET" "BYPRODUCTS" ${ARGN})
- if(NOT DEFINED TB_TARGET)
- message(FATAL_ERROR "target_byproducts() missing parameter: TARGET <target>")
- endif()
- add_custom_command(TARGET ${TB_TARGET}
- POST_BUILD COMMAND ${CMAKE_COMMAND} -E echo ""
- BYPRODUCTS ${TB_BYPRODUCTS}
- COMMENT "Logical command for additional byproducts on target: ${TB_TARGET}"
- )
- endfunction()
- ########################################################
- # 4. Zephyr devicetree function
- ########################################################
- # 4.1. dt_*
- #
- # The following methods are for retrieving devicetree information in CMake.
- #
- # Note: In CMake we refer to the nodes using the node's path, therefore there
- # is no dt_path(...) function for obtaining a node identifier.
- # Usage:
- # dt_nodelabel(<var> NODELABEL <label>)
- #
- # Function for retrieving the node path for the node having nodelabel
- # <label>.
- #
- # Example devicetree fragment:
- #
- # / {
- # soc {
- # nvic: interrupt-controller@e000e100 { ... };
- # };
- # };
- #
- # Example usage:
- #
- # # Sets 'nvic_path' to "/soc/interrupt-controller@e000e100"
- # dt_nodelabel(nvic_path NODELABEL "nvic")
- #
- # The node's path will be returned in the <var> parameter.
- # <var> will be undefined if node does not exist.
- #
- # <var> : Return variable where the node path will be stored
- # NODELABEL <label> : Node label
- function(dt_nodelabel var)
- set(req_single_args "NODELABEL")
- cmake_parse_arguments(DT_LABEL "" "${req_single_args}" "" ${ARGN})
- if(${ARGV0} IN_LIST req_single_args)
- message(FATAL_ERROR "dt_nodelabel(${ARGV0} ...) missing return parameter.")
- endif()
- foreach(arg ${req_single_args})
- if(NOT DEFINED DT_LABEL_${arg})
- message(FATAL_ERROR "dt_nodelabel(${ARGV0} ...) "
- "missing required argument: ${arg}"
- )
- endif()
- endforeach()
- get_target_property(${var} devicetree_target "DT_NODELABEL|${DT_LABEL_NODELABEL}")
- if(${${var}} STREQUAL ${var}-NOTFOUND)
- set(${var})
- endif()
- set(${var} ${${var}} PARENT_SCOPE)
- endfunction()
- # Usage:
- # dt_node_exists(<var> PATH <path>)
- #
- # Tests whether a node with path <path> exists in the devicetree.
- #
- # The result of the check, either TRUE or FALSE, will be returned in
- # the <var> parameter.
- #
- # <var> : Return variable where the check result will be returned
- # PATH <path> : Node path
- function(dt_node_exists var)
- set(req_single_args "PATH")
- cmake_parse_arguments(DT_NODE "" "${req_single_args}" "" ${ARGN})
- if(${ARGV0} IN_LIST req_single_args)
- message(FATAL_ERROR "dt_node_existsl(${ARGV0} ...) missing return parameter.")
- endif()
- foreach(arg ${req_single_args})
- if(NOT DEFINED DT_NODE_${arg})
- message(FATAL_ERROR "dt_node_exists(${ARGV0} ...) "
- "missing required argument: ${arg}"
- )
- endif()
- endforeach()
- get_target_property(${var} devicetree_target "DT_NODE|${DT_NODE_PATH}")
- if(${var})
- set(${var} ${${var}} PARENT_SCOPE)
- else()
- set(${var} FALSE PARENT_SCOPE)
- endif()
- endfunction()
- # Usage:
- # dt_node_has_status(<var> PATH <path> STATUS <status>)
- #
- # Tests whether <path> refers to a node which:
- # - exists in the devicetree, and
- # - has a status property matching the <status> argument
- # (a missing status or an “ok” status is treated as if it
- # were “okay” instead)
- #
- # The result of the check, either TRUE or FALSE, will be returned in
- # the <var> parameter.
- #
- # <var> : Return variable where the check result will be returned
- # PATH <path> : Node path
- # STATUS <status> : Status to check
- function(dt_node_has_status var)
- set(req_single_args "PATH;STATUS")
- cmake_parse_arguments(DT_NODE "" "${req_single_args}" "" ${ARGN})
- if(${ARGV0} IN_LIST req_single_args)
- message(FATAL_ERROR "dt_node_has_status(${ARGV0} ...) missing return parameter.")
- endif()
- foreach(arg ${req_single_args})
- if(NOT DEFINED DT_NODE_${arg})
- message(FATAL_ERROR "dt_node_has_status(${ARGV0} ...) "
- "missing required argument: ${arg}"
- )
- endif()
- endforeach()
- dt_node_exists(${var} PATH ${DT_NODE_PATH})
- if(NOT ${${var}})
- set(${var} FALSE PARENT_SCOPE)
- endif()
- dt_prop(${var} PATH ${DT_NODE_PATH} PROPERTY status)
- if(NOT DEFINED ${var} OR "${${var}}" STREQUAL ok)
- set(${var} okay)
- endif()
- if(${var} STREQUAL ${DT_NODE_STATUS})
- set(${var} TRUE PARENT_SCOPE)
- else()
- set(${var} FALSE PARENT_SCOPE)
- endif()
- endfunction()
- # Usage:
- #
- # dt_prop(<var> PATH <path> PROPERTY <prop> [INDEX <idx>])
- #
- # Get a devicetree property value. The value will be returned in the
- # <var> parameter.
- #
- # This function currently only supports properties with the following
- # devicetree binding types: string, int, boolean, array, uint8-array,
- # string-array, path.
- #
- # For array valued properties (including uint8-array and
- # string-array), the entire array is returned as a CMake list unless
- # INDEX is given. If INDEX is given, just the array element at index
- # <idx> is returned.
- #
- # The property value will be returned in the <var> parameter if the
- # node exists and has a property <prop> with one of the above types.
- # <var> will be undefined otherwise.
- #
- # To test if the property is defined before using it, use DEFINED on
- # the return <var>, like this:
- #
- # dt_prop(reserved_ranges PATH "/soc/gpio@deadbeef" PROPERTY "gpio-reserved-ranges")
- # if(DEFINED reserved_ranges)
- # # Node exists and has the "gpio-reserved-ranges" property.
- # endif()
- #
- # To distinguish a missing node from a missing property, combine
- # dt_prop() and dt_node_exists(), like this:
- #
- # dt_node_exists(node_exists PATH "/soc/gpio@deadbeef")
- # dt_prop(reserved_ranges PATH "/soc/gpio@deadbeef" PROPERTY "gpio-reserved-ranges")
- # if(DEFINED reserved_ranges)
- # # Node "/soc/gpio@deadbeef" exists and has the "gpio-reserved-ranges" property
- # elseif(node_exists)
- # # Node exists, but doesn't have the property, or the property has an unsupported type.
- # endif()
- #
- # <var> : Return variable where the property value will be stored
- # PATH <path> : Node path
- # PROPERTY <prop>: Property for which a value should be returned, as it
- # appears in the DTS source
- # INDEX <idx> : Optional index when retrieving a value in an array property
- function(dt_prop var)
- set(req_single_args "PATH;PROPERTY")
- set(single_args "INDEX")
- cmake_parse_arguments(DT_PROP "" "${req_single_args};${single_args}" "" ${ARGN})
- if(${ARGV0} IN_LIST req_single_args)
- message(FATAL_ERROR "dt_prop(${ARGV0} ...) missing return parameter.")
- endif()
- foreach(arg ${req_single_args})
- if(NOT DEFINED DT_PROP_${arg})
- message(FATAL_ERROR "dt_prop(${ARGV0} ...) "
- "missing required argument: ${arg}"
- )
- endif()
- endforeach()
- get_property(exists TARGET devicetree_target
- PROPERTY "DT_PROP|${DT_PROP_PATH}|${DT_PROP_PROPERTY}"
- SET
- )
- if(NOT exists)
- set(${var} PARENT_SCOPE)
- return()
- endif()
- get_target_property(val devicetree_target
- "DT_PROP|${DT_PROP_PATH}|${DT_PROP_PROPERTY}"
- )
- if(DEFINED DT_PROP_INDEX)
- list(GET val ${DT_PROP_INDEX} element)
- set(${var} "${element}" PARENT_SCOPE)
- else()
- set(${var} "${val}" PARENT_SCOPE)
- endif()
- endfunction()
- # Usage:
- # dt_num_regs(<var> PATH <path>)
- #
- # Get the number of register blocks in the node's reg property;
- # this may be zero.
- #
- # The value will be returned in the <var> parameter.
- #
- # <var> : Return variable where the property value will be stored
- # PATH <path> : Node path
- function(dt_num_regs var)
- set(req_single_args "PATH")
- cmake_parse_arguments(DT_REG "" "${req_single_args}" "" ${ARGN})
- if(${ARGV0} IN_LIST req_single_args)
- message(FATAL_ERROR "dt_num_regs(${ARGV0} ...) missing return parameter.")
- endif()
- foreach(arg ${req_single_args})
- if(NOT DEFINED DT_REG_${arg})
- message(FATAL_ERROR "dt_num_regs(${ARGV0} ...) "
- "missing required argument: ${arg}"
- )
- endif()
- endforeach()
- get_target_property(${var} devicetree_target "DT_REG|${DT_REG_PATH}|NUM")
- set(${var} ${${var}} PARENT_SCOPE)
- endfunction()
- # Usage:
- # dt_reg_addr(<var> PATH <path> [INDEX <idx>])
- #
- # Get the base address of the register block at index <idx>.
- # If <idx> is omitted, then the value at index 0 will be returned.
- #
- # The value will be returned in the <var> parameter.
- #
- # Results can be:
- # - The base address of the register block
- # - <var> will be undefined if node does not exists or does not have a register
- # block at the requested index.
- #
- # <var> : Return variable where the address value will be stored
- # PATH <path> : Node path
- # INDEX <idx> : Index number
- function(dt_reg_addr var)
- set(req_single_args "PATH")
- set(single_args "INDEX")
- cmake_parse_arguments(DT_REG "" "${req_single_args};${single_args}" "" ${ARGN})
- if(${ARGV0} IN_LIST req_single_args)
- message(FATAL_ERROR "dt_reg_addr(${ARGV0} ...) missing return parameter.")
- endif()
- foreach(arg ${req_single_args})
- if(NOT DEFINED DT_REG_${arg})
- message(FATAL_ERROR "dt_reg_addr(${ARGV0} ...) "
- "missing required argument: ${arg}"
- )
- endif()
- endforeach()
- if(NOT DEFINED DT_REG_INDEX)
- set(DT_REG_INDEX 0)
- endif()
- get_target_property(${var}_list devicetree_target "DT_REG|${DT_REG_PATH}|ADDR")
- list(GET ${var}_list ${DT_REG_INDEX} ${var})
- if("${var}" STREQUAL NONE)
- set(${var})
- endif()
- set(${var} ${${var}} PARENT_SCOPE)
- endfunction()
- # Usage:
- # dt_reg_size(<var> PATH <path> [INDEX <idx>])
- #
- # Get the size of the register block at index <idx>.
- # If INDEX is omitted, then the value at index 0 will be returned.
- #
- # The value will be returned in the <value> parameter.
- #
- # <var> : Return variable where the size value will be stored
- # PATH <path> : Node path
- # INDEX <idx> : Index number
- function(dt_reg_size var)
- set(req_single_args "PATH")
- set(single_args "INDEX")
- cmake_parse_arguments(DT_REG "" "${req_single_args};${single_args}" "" ${ARGN})
- if(${ARGV0} IN_LIST req_single_args)
- message(FATAL_ERROR "dt_reg_size(${ARGV0} ...) missing return parameter.")
- endif()
- foreach(arg ${req_single_args})
- if(NOT DEFINED DT_REG_${arg})
- message(FATAL_ERROR "dt_reg_size(${ARGV0} ...) "
- "missing required argument: ${arg}"
- )
- endif()
- endforeach()
- if(NOT DEFINED DT_REG_INDEX)
- set(DT_REG_INDEX 0)
- endif()
- get_target_property(${var}_list devicetree_target "DT_REG|${DT_REG_PATH}|SIZE")
- list(GET ${var}_list ${DT_REG_INDEX} ${var})
- if("${var}" STREQUAL NONE)
- set(${var})
- endif()
- set(${var} ${${var}} PARENT_SCOPE)
- endfunction()
- # Usage:
- # dt_has_chosen(<var> PROPERTY <prop>)
- #
- # Test if the devicetree's /chosen node has a given property
- # <prop> which contains the path to a node.
- #
- # Example devicetree fragment:
- #
- # chosen {
- # foo = &bar;
- # };
- #
- # Example usage:
- #
- # # Sets 'result' to TRUE
- # dt_has_chosen(result PROPERTY "foo")
- #
- # # Sets 'result' to FALSE
- # dt_has_chosen(result PROPERTY "baz")
- #
- # The result of the check, either TRUE or FALSE, will be stored in the
- # <var> parameter.
- #
- # <var> : Return variable
- # PROPERTY <prop> : Chosen property
- function(dt_has_chosen var)
- set(req_single_args "PROPERTY")
- cmake_parse_arguments(DT_CHOSEN "" "${req_single_args}" "" ${ARGN})
- if(${ARGV0} IN_LIST req_single_args)
- message(FATAL_ERROR "dt_has_chosen(${ARGV0} ...) missing return parameter.")
- endif()
- foreach(arg ${req_single_args})
- if(NOT DEFINED DT_CHOSEN_${arg})
- message(FATAL_ERROR "dt_has_chosen(${ARGV0} ...) "
- "missing required argument: ${arg}"
- )
- endif()
- endforeach()
- get_target_property(exists devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
- if(${exists} STREQUAL exists-NOTFOUND)
- set(${var} FALSE PARENT_SCOPE)
- else()
- set(${var} TRUE PARENT_SCOPE)
- endif()
- endfunction()
- # Usage:
- # dt_chosen(<var> PROPERTY <prop>)
- #
- # Get a node path for a /chosen node property.
- #
- # the node path will be returned in the <value> parameter.
- #
- # <var> : Return variable where the node path will be stored
- # PROPERTY <prop> : Chosen property
- function(dt_chosen var)
- set(req_single_args "PROPERTY")
- cmake_parse_arguments(DT_CHOSEN "" "${req_single_args}" "" ${ARGN})
- if(${ARGV0} IN_LIST req_single_args)
- message(FATAL_ERROR "dt_has_chosen(${ARGV0} ...) missing return parameter.")
- endif()
- foreach(arg ${req_single_args})
- if(NOT DEFINED DT_CHOSEN_${arg})
- message(FATAL_ERROR "dt_chosen(${ARGV0} ...) "
- "missing required argument: ${arg}"
- )
- endif()
- endforeach()
- get_target_property(${var} devicetree_target "DT_CHOSEN|${DT_CHOSEN_PROPERTY}")
- if(${${var}} STREQUAL ${var}-NOTFOUND)
- set(${var} PARENT_SCOPE)
- else()
- set(${var} ${${var}} PARENT_SCOPE)
- endif()
- endfunction()
- ########################################################
- # 5. Zephyr linker function
- ########################################################
- # 5.1. zephyr_linker*
- #
- # The following methods are for defining linker structure using CMake functions.
- #
- # This allows Zephyr developers to define linker sections and their content and
- # have this configuration rendered into an appropriate linker script based on
- # the toolchain in use.
- # For example:
- # ld linker scripts with GNU ld
- # ARM scatter files with ARM linker.
- #
- # Example usage:
- # zephyr_linker_section(
- # NAME my_data
- # VMA RAM
- # LMA FLASH
- # )
- #
- # and to configure special input sections for the section
- # zephyr_linker_section_configure(
- # SECTION my_data
- # INPUT "my_custom_data"
- # KEEP
- # )
- # Usage:
- # zephyr_linker([FORMAT <format>]
- # [ENTRY <entry symbol>]
- # )
- #
- # Zephyr linker general settings.
- # This function specifies general settings for the linker script to be generated.
- #
- # FORMAT <format>: The output format of the linked executable.
- # ENTRY <entry symbolformat>: The code entry symbol.
- #
- function(zephyr_linker)
- set(single_args "ENTRY;FORMAT")
- cmake_parse_arguments(LINKER "" "${single_args}" "" ${ARGN})
- if(LINKER_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "zephyr_linker(${ARGV0} ...) given unknown "
- "arguments: ${LINKER_UNPARSED_ARGUMENTS}"
- )
- endif()
- if(DEFINED LINKER_FORMAT)
- get_property(format_defined TARGET linker PROPERTY FORMAT SET)
- if(format_defined)
- message(FATAL_ERROR "zephyr_linker(FORMAT ...) already configured.")
- else()
- set_property(TARGET linker PROPERTY FORMAT ${LINKER_FORMAT})
- endif()
- endif()
- if(DEFINED LINKER_ENTRY)
- get_property(entry_defined TARGET linker PROPERTY ENTRY SET)
- if(entry_defined)
- message(FATAL_ERROR "zephyr_linker(ENTRY ...) already configured.")
- else()
- set_property(TARGET linker PROPERTY ENTRY ${LINKER_ENTRY})
- endif()
- endif()
- endfunction()
- # Usage:
- # zephyr_linker_memory(NAME <name> START <address> SIZE <size> FLAGS <flags>)
- #
- # Zephyr linker memory.
- # This function specifies a memory region for the platform in use.
- #
- # Note:
- # This function should generally be called with values obtained from
- # devicetree or Kconfig.
- #
- # NAME <name> : Name of the memory region, for example FLASH.
- # START <address>: Start address of the memory region.
- # Start address can be given as decimal or hex value.
- # SIZE <size> : Size of the memory region.
- # Size can be given as decimal value, hex value, or decimal with postfix k or m.
- # All the following are valid values:
- # 1048576, 0x10000, 1024k, 1024K, 1m, and 1M.
- # FLAGS <flags> : Flags describing properties of the memory region.
- # Currently supported:
- # r: Read-only region
- # w: Read-write region
- # x: Executable region
- # The flags r and x, or w and x may be combined like: rx, wx.
- function(zephyr_linker_memory)
- set(single_args "FLAGS;NAME;SIZE;START")
- cmake_parse_arguments(MEMORY "" "${single_args}" "" ${ARGN})
- if(MEMORY_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "zephyr_linker_memory(${ARGV0} ...) given unknown "
- "arguments: ${MEMORY_UNPARSED_ARGUMENTS}"
- )
- endif()
- foreach(arg ${single_args})
- if(NOT DEFINED MEMORY_${arg})
- message(FATAL_ERROR "zephyr_linker_memory(${ARGV0} ...) missing required "
- "argument: ${arg}"
- )
- endif()
- endforeach()
- set(MEMORY)
- zephyr_linker_arg_val_list(MEMORY "${single_args}")
- string(REPLACE ";" "\;" MEMORY "${MEMORY}")
- set_property(TARGET linker
- APPEND PROPERTY MEMORY_REGIONS "{${MEMORY}}"
- )
- endfunction()
- # Usage:
- # zephyr_linker_memory_ifdef(<setting> NAME <name> START <address> SIZE <size> FLAGS <flags>)
- #
- # Will create memory region if <setting> is enabled.
- #
- # <setting>: Setting to check for True value before invoking
- # zephyr_linker_memory()
- #
- # See zephyr_linker_memory() description for other supported arguments.
- #
- macro(zephyr_linker_memory_ifdef feature_toggle)
- if(${${feature_toggle}})
- zephyr_linker_memory(${ARGN})
- endif()
- endmacro()
- # Usage:
- # zephyr_linker_dts_memory(NAME <name> PATH <path> FLAGS <flags>)
- # zephyr_linker_dts_memory(NAME <name> NODELABEL <nodelabel> FLAGS <flags>)
- # zephyr_linker_dts_memory(NAME <name> CHOSEN <prop> FLAGS <flags>)
- #
- # Zephyr linker devicetree memory.
- # This function specifies a memory region for the platform in use based on its
- # devicetree configuration.
- #
- # The memory will only be defined if the devicetree node or a devicetree node
- # matching the nodelabel exists and has status okay.
- #
- # Only one of PATH, NODELABEL, and CHOSEN parameters may be given.
- #
- # NAME <name> : Name of the memory region, for example FLASH.
- # PATH <path> : Devicetree node identifier.
- # NODELABEL <label>: Node label
- # CHOSEN <prop> : Chosen property, add memory section described by the
- # /chosen property if it exists.
- # FLAGS <flags> : Flags describing properties of the memory region.
- # Currently supported:
- # r: Read-only region
- # w: Read-write region
- # x: Executable region
- # The flags r and x, or w and x may be combined like: rx, wx.
- #
- function(zephyr_linker_dts_memory)
- set(single_args "CHOSEN;FLAGS;NAME;PATH;NODELABEL")
- cmake_parse_arguments(DTS_MEMORY "" "${single_args}" "" ${ARGN})
- if(DTS_MEMORY_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "zephyr_linker_dts_memory(${ARGV0} ...) given unknown "
- "arguments: ${DTS_MEMORY_UNPARSED_ARGUMENTS}"
- )
- endif()
- if((DEFINED DTS_MEMORY_PATH AND (DEFINED DTS_MEMORY_NODELABEL OR DEFINED DTS_MEMORY_CHOSEN))
- OR (DEFINED DTS_MEMORY_NODELABEL AND DEFINED DTS_MEMORY_CHOSEN))
- message(FATAL_ERROR "zephyr_linker_dts_memory(${ARGV0} ...), only one of "
- "PATH, NODELABEL, and CHOSEN is allowed."
- )
- endif()
- if(DEFINED DTS_MEMORY_NODELABEL)
- dt_nodelabel(DTS_MEMORY_PATH NODELABEL ${DTS_MEMORY_NODELABEL})
- endif()
- if(DEFINED DTS_MEMORY_CHOSEN)
- dt_chosen(DTS_MEMORY_PATH PROPERTY ${DTS_MEMORY_CHOSEN})
- endif()
- if(NOT DEFINED DTS_MEMORY_PATH)
- return()
- endif()
- dt_node_exists(exists PATH ${DTS_MEMORY_PATH})
- if(NOT ${exists})
- return()
- endif()
- dt_reg_addr(addr PATH ${DTS_MEMORY_PATH})
- dt_reg_size(size PATH ${DTS_MEMORY_PATH})
- zephyr_linker_memory(
- NAME ${DTS_MEMORY_NAME}
- START ${addr}
- SIZE ${size}
- FLAGS ${DTS_MEMORY_FLAGS}
- )
- endfunction()
- # Usage:
- # zephyr_linker_group(NAME <name> [VMA <region|group>] [LMA <region|group>] [SYMBOL <SECTION>])
- # zephyr_linker_group(NAME <name> GROUP <group> [SYMBOL <SECTION>])
- #
- # Zephyr linker group.
- # This function specifies a group inside a memory region or another group.
- #
- # The group ensures that all section inside the group are located together inside
- # the specified group.
- #
- # This also allows for section placement inside a given group without the section
- # itself needing the precise knowledge regarding the exact memory region this
- # section will be placed in, as that will be determined by the group setup.
- #
- # Each group will define the following linker symbols:
- # __<name>_start : Start address of the group
- # __<name>_end : End address of the group
- # __<name>_size : Size of the group
- #
- # Note: <name> will be converted to lower casing for linker symbols definitions.
- #
- # NAME <name> : Name of the group.
- # VMA <region|group> : VMA Memory region or group to be used for this group.
- # If a group is used then the VMA region of that group will be used.
- # LMA <region|group> : Memory region or group to be used for this group.
- # GROUP <group> : Place the new group inside the existing group <group>
- # SYMBOL <SECTION> : Specify that start symbol of the region should be identical
- # to the start address of the first section in the group.
- #
- # Note: VMA and LMA are mutual exclusive with GROUP
- #
- # Example:
- # zephyr_linker_memory(NAME memA START ... SIZE ... FLAGS ...)
- # zephyr_linker_group(NAME groupA LMA memA)
- # zephyr_linker_group(NAME groupB LMA groupA)
- #
- # will create two groups in same memory region as groupB will inherit the LMA
- # from groupA:
- #
- # +-----------------+
- # | memory region A |
- # | |
- # | +-------------+ |
- # | | groupA | |
- # | +-------------+ |
- # | |
- # | +-------------+ |
- # | | groupB | |
- # | +-------------+ |
- # | |
- # +-----------------+
- #
- # whereas
- # zephyr_linker_memory(NAME memA START ... SIZE ... FLAGS ...)
- # zephyr_linker_group(NAME groupA LMA memA)
- # zephyr_linker_group(NAME groupB GROUP groupA)
- #
- # will create groupB inside groupA:
- #
- # +---------------------+
- # | memory region A |
- # | |
- # | +-----------------+ |
- # | | groupA | |
- # | | | |
- # | | +-------------+ | |
- # | | | groupB | | |
- # | | +-------------+ | |
- # | | | |
- # | +-----------------+ |
- # | |
- # +---------------------+
- function(zephyr_linker_group)
- set(single_args "NAME;GROUP;LMA;SYMBOL;VMA")
- set(symbol_values SECTION)
- cmake_parse_arguments(GROUP "" "${single_args}" "" ${ARGN})
- if(GROUP_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "zephyr_linker_group(${ARGV0} ...) given unknown "
- "arguments: ${GROUP_UNPARSED_ARGUMENTS}"
- )
- endif()
- if(DEFINED GROUP_GROUP AND (DEFINED GROUP_VMA OR DEFINED GROUP_LMA))
- message(FATAL_ERROR "zephyr_linker_group(GROUP ...) cannot be used with "
- "VMA or LMA"
- )
- endif()
- if(DEFINED GROUP_SYMBOL)
- if(NOT ${GROUP_SYMBOL} IN_LIST symbol_values)
- message(FATAL_ERROR "zephyr_linker_group(SYMBOL ...) given unknown value")
- endif()
- endif()
- set(GROUP)
- zephyr_linker_arg_val_list(GROUP "${single_args}")
- string(REPLACE ";" "\;" GROUP "${GROUP}")
- set_property(TARGET linker
- APPEND PROPERTY GROUPS "{${GROUP}}"
- )
- endfunction()
- # Usage:
- # zephyr_linker_section(NAME <name> [GROUP <group>]
- # [VMA <region|group>] [LMA <region|group>]
- # [ADDRESS <address>] [ALIGN <alignment>]
- # [SUBALIGN <alignment>] [FLAGS <flags>]
- # [HIDDEN] [NOINPUT] [NOINIT]
- # [PASS <no> [<no>...]
- # )
- #
- # Zephyr linker output section.
- # This function specifies an output section for the linker.
- #
- # When using zephyr_linker_section(NAME <name>) an output section with <name>
- # will be configured. This section will default include input sections of the
- # same name, unless NOINPUT is specified.
- # This means the section named `foo` will default include the sections matching
- # `foo` and `foo.*`
- # Each output section will define the following linker symbols:
- # __<name>_start : Start address of the section
- # __<name>_end : End address of the section
- # __<name>_size : Size of the section
- # __<name>_load_start : Load address of the section, if VMA = LMA then this
- # value will be identical to `__<name>_start`
- #
- # The location of the output section can be controlled using LMA, VMA, and
- # address parameters
- #
- # NAME <name> : Name of the output section.
- # VMA <region|group> : VMA Memory region or group where code / data is located runtime (VMA)
- # If <group> is used here it means the section will use the
- # same VMA memory region as <group> but will not be placed
- # inside the group itself, see also GROUP argument.
- # KVMA <region|group> : Kernel VMA Memory region or group where code / data is located runtime (VMA)
- # When MMU is active and Kernel VM base and offset is different
- # from SRAM base and offset, then the region defined by KVMA will
- # be used as VMA.
- # If <group> is used here it means the section will use the
- # same VMA memory region as <group> but will not be placed
- # inside the group itself, see also GROUP argument.
- # LMA <region|group> : Memory region or group where code / data is loaded (LMA)
- # If VMA is different from LMA, the code / data will be loaded
- # from LMA into VMA at bootup, this is usually the case for
- # global or static variables that are loaded in rom and copied
- # to ram at boot time.
- # If <group> is used here it means the section will use the
- # same LMA memory region as <group> but will not be placed
- # inside the group itself, see also GROUP argument.
- # GROUP <group> : Place this section inside the group <group>
- # ADDRESS <address> : Specific address to use for this section.
- # ALIGN_WITH_INPUT : The alignment difference between VMA and LMA is kept
- # intact for this section.
- # ALIGN <alignment> : Align the execution address with alignment.
- # SUBALIGN <alignment>: Align input sections with alignment value.
- # ENDALIGN <alignment>: Align the end so that next output section will start aligned.
- # This only has effect on Scatter scripts.
- # Note: Regarding all alignment attributes. Not all linkers may handle alignment
- # in identical way. For example the Scatter file will align both load and
- # execution address (LMA and VMA) to be aligned when given the ALIGN attribute.
- # NOINPUT : No default input sections will be defined, to setup input
- # sections for section <name>, the corresponding
- # `zephyr_linker_section_configure()` must be used.
- # PASS <no> [<no> ..] : Linker pass iteration where this section should be active.
- # Default a section will be present during all linker passes
- # But in cases a section shall only be present at a specific
- # pass, this argument can be used. For example to only have
- # this section present on the first linker pass, use `PASS 1`.
- #
- # Note: VMA and LMA are mutual exclusive with GROUP
- #
- function(zephyr_linker_section)
- set(options "ALIGN_WITH_INPUT;HIDDEN;NOINIT;NOINPUT")
- set(single_args "ADDRESS;ALIGN;ENDALIGN;GROUP;KVMA;LMA;NAME;SUBALIGN;TYPE;VMA")
- set(multi_args "PASS")
- cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN})
- if(SECTION_UNPARSED_ARGUMENTS)
- message(WARNING "zephyr_linker_section(${ARGV0} ...) given unknown "
- "arguments: ${SECTION_UNPARSED_ARGUMENTS}"
- )
- endif()
- if(DEFINED SECTION_GROUP AND (DEFINED SECTION_VMA OR DEFINED SECTION_LMA))
- message(FATAL_ERROR "zephyr_linker_section(GROUP ...) cannot be used with "
- "VMA or LMA"
- )
- endif()
- if(DEFINED SECTION_KVMA)
- # If KVMA is set and the Kernel virtual memory settings reqs are met, we
- # substitute the VMA setting with the specified KVMA value.
- if(CONFIG_MMU)
- math(EXPR KERNEL_MEM_VM_OFFSET
- "(${CONFIG_KERNEL_VM_BASE} + ${CONFIG_KERNEL_VM_OFFSET})\
- - (${CONFIG_SRAM_BASE_ADDRESS} + ${CONFIG_SRAM_OFFSET})"
- )
- if(NOT (${KERNEL_MEM_VM_OFFSET} EQUAL 0))
- set(SECTION_VMA ${SECTION_KVMA})
- set(SECTION_KVMA)
- endif()
- endif()
- endif()
- set(SECTION)
- zephyr_linker_arg_val_list(SECTION "${single_args}")
- zephyr_linker_arg_val_list(SECTION "${options}")
- zephyr_linker_arg_val_list(SECTION "${multi_args}")
- string(REPLACE ";" "\;" SECTION "${SECTION}")
- set_property(TARGET linker
- APPEND PROPERTY SECTIONS "{${SECTION}}"
- )
- endfunction()
- # Usage:
- # zephyr_linker_section_ifdef(<setting>
- # NAME <name> [VMA <region>] [LMA <region>]
- # [ADDRESS <address>] [ALIGN <alignment>]
- # [SUBALIGN <alignment>] [FLAGS <flags>]
- # [HIDDEN] [NOINPUT] [NOINIT]
- # [PASS <no> [<no>...]
- # )
- #
- # Will create an output section if <setting> is enabled.
- #
- # <setting>: Setting to check for True value before invoking
- # zephyr_linker_section()
- #
- # See zephyr_linker_section() description for other supported arguments.
- #
- macro(zephyr_linker_section_ifdef feature_toggle)
- if(${${feature_toggle}})
- zephyr_linker_section(${ARGN})
- endif()
- endmacro()
- # Usage:
- # zephyr_iterable_section(NAME <name> [GROUP <group>]
- # [VMA <region|group>] [LMA <region|group>]
- # [ALIGN_WITH_INPUT] [SUBALIGN <alignment>]
- # )
- #
- #
- # Define an output section which will set up an iterable area
- # of equally-sized data structures. For use with Z_STRUCT_SECTION_ITERABLE.
- # Input sections will be sorted by name in lexicographical order.
- #
- # Each list for an input section will define the following linker symbols:
- # _<name>_list_start: Start of the iterable list
- # _<name>_list_end : End of the iterable list
- #
- # The output section will be named `<name>_area` and define the following linker
- # symbols:
- # __<name>_area_start : Start address of the section
- # __<name>_area_end : End address of the section
- # __<name>_area_size : Size of the section
- # __<name>_area_load_start : Load address of the section, if VMA = LMA then this
- # value will be identical to `__<name>_area_start`
- #
- # NAME <name> : Name of the struct type, the output section be named
- # accordingly as: <name>_area.
- # VMA <region|group> : VMA Memory region where code / data is located runtime (VMA)
- # LMA <region|group> : Memory region where code / data is loaded (LMA)
- # If VMA is different from LMA, the code / data will be loaded
- # from LMA into VMA at bootup, this is usually the case for
- # global or static variables that are loaded in rom and copied
- # to ram at boot time.
- # GROUP <group> : Place this section inside the group <group>
- # ADDRESS <address> : Specific address to use for this section.
- # ALIGN_WITH_INPUT : The alignment difference between VMA and LMA is kept
- # intact for this section.
- # SUBALIGN <alignment>: Force input alignment with size <alignment>
- # Note: Regarding all alignment attributes. Not all linkers may handle alignment
- # in identical way. For example the Scatter file will align both load and
- # execution address (LMA and VMA) to be aligned when given the ALIGN attribute.
- #/
- function(zephyr_iterable_section)
- # ToDo - Should we use ROM, RAM, etc as arguments ?
- set(options "ALIGN_WITH_INPUT")
- set(single_args "GROUP;LMA;NAME;SUBALIGN;VMA")
- set(multi_args "")
- set(align_input)
- cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN})
- if(NOT DEFINED SECTION_NAME)
- message(FATAL_ERROR "zephyr_iterable_section(${ARGV0} ...) missing "
- "required argument: NAME"
- )
- endif()
- if(NOT DEFINED SECTION_SUBALIGN)
- message(FATAL_ERROR "zephyr_iterable_section(${ARGV0} ...) missing "
- "required argument: SUBALIGN"
- )
- endif()
- if(SECTION_ALIGN_WITH_INPUT)
- set(align_input ALIGN_WITH_INPUT)
- endif()
- zephyr_linker_section(
- NAME ${SECTION_NAME}_area
- GROUP "${SECTION_GROUP}"
- VMA "${SECTION_VMA}" LMA "${SECTION_LMA}"
- NOINPUT ${align_input} SUBALIGN ${SECTION_SUBALIGN}
- )
- zephyr_linker_section_configure(
- SECTION ${SECTION_NAME}_area
- INPUT "._${SECTION_NAME}.static.*"
- SYMBOLS _${SECTION_NAME}_list_start _${SECTION_NAME}_list_end
- KEEP SORT NAME
- )
- endfunction()
- # Usage:
- # zephyr_linker_section_obj_level(SECTION <section> LEVEL <level>)
- #
- # generate a symbol to mark the start of the objects array for
- # the specified object and level, then link all of those objects
- # (sorted by priority). Ensure the objects aren't discarded if there is
- # no direct reference to them.
- #
- # This is useful content such as struct devices.
- #
- # For example: zephyr_linker_section_obj_level(SECTION init LEVEL PRE_KERNEL_1)
- # will create an input section matching `.z_init_PRE_KERNEL_1?_` and
- # `.z_init_PRE_KERNEL_1??_`.
- #
- # SECTION <section>: Section in which the objects shall be placed
- # LEVEL <level> : Priority level, all input sections matching the level
- # will be sorted.
- #
- function(zephyr_linker_section_obj_level)
- set(single_args "SECTION;LEVEL")
- cmake_parse_arguments(OBJ "" "${single_args}" "" ${ARGN})
- if(NOT DEFINED OBJ_SECTION)
- message(FATAL_ERROR "zephyr_linker_section_obj_level(${ARGV0} ...) "
- "missing required argument: SECTION"
- )
- endif()
- if(NOT DEFINED OBJ_LEVEL)
- message(FATAL_ERROR "zephyr_linker_section_obj_level(${ARGV0} ...) "
- "missing required argument: LEVEL"
- )
- endif()
- zephyr_linker_section_configure(
- SECTION ${OBJ_SECTION}
- INPUT ".z_${OBJ_SECTION}_${OBJ_LEVEL}?_"
- SYMBOLS __${OBJ_SECTION}_${OBJ_LEVEL}_start
- KEEP SORT NAME
- )
- zephyr_linker_section_configure(
- SECTION ${OBJ_SECTION}
- INPUT ".z_${OBJ_SECTION}_${OBJ_LEVEL}??_"
- KEEP SORT NAME
- )
- endfunction()
- # Usage:
- # zephyr_linker_section_configure(SECTION <section> [ALIGN <alignment>]
- # [PASS <no>] [PRIO <no>] [SORT <sort>]
- # [ANY] [FIRST] [KEEP]
- # )
- #
- # Configure an output section with additional input sections.
- # An output section can be configured with additional input sections besides its
- # default section.
- # For example, adding the input section `foo` to the output section bar, with KEEP
- # attribute, then call:
- # zephyr_linker_section_configure(SECTION bar INPUT foo KEEP)
- #
- # ALIGN <alignment> : Will align the input section placement inside the load
- # region with <alignment>
- # FIRST : The first input section in the list should be marked as
- # first section in output.
- # SORT <NAME> : Sort the input sections according to <type>.
- # Currently only `NAME` is supported.
- # KEEP : Do no eliminate input section during linking
- # PRIO : The priority of the input section. Per default, input
- # sections order is not guaranteed by all linkers, but
- # using priority, then Zephyr CMake linker will create
- # sections so order can be guaranteed. All unprioritized
- # sections will internally be given a CMake process order
- # priority counting from 100, so first unprioritized section
- # is handles internal pri0 100, next 101, and so on.
- # To ensure a specific input section come before those,
- # you may use `PRIO 50`, `PRIO 20` and so on.
- # To ensure an input section is at the end, it is advised
- # to use `PRIO 200` and above.
- # PASS <no> : The call should only be considered for linker pass number <no>.
- # For example, `PASS 1` means the call is only effective
- # on first linker pass iteration. `PASS 2` on second iteration,
- # and so on.
- # FLAGS <flags> : Special section flags such as "+RO", +XO, "+ZI".
- # ANY : ANY section flag in scatter file.
- # The FLAGS and ANY arguments only has effect for scatter files.
- #
- function(zephyr_linker_section_configure)
- set(options "ANY;FIRST;KEEP")
- set(single_args "ALIGN;OFFSET;PASS;PRIO;SECTION;SORT")
- set(multi_args "FLAGS;INPUT;SYMBOLS")
- cmake_parse_arguments(SECTION "${options}" "${single_args}" "${multi_args}" ${ARGN})
- if(SECTION_UNPARSED_ARGUMENTS)
- message(FATAL_ERROR "zephyr_linker_section_configure(${ARGV0} ...) given unknown arguments: ${SECTION_UNPARSED_ARGUMENTS}")
- endif()
- if(DEFINED SECTION_SYMBOLS)
- list(LENGTH SECTION_SYMBOLS symbols_count)
- if(${symbols_count} GREATER 2)
- message(FATAL_ERROR "zephyr_linker_section_configure(SYMBOLS [start_sym [end_sym]]) takes maximum two symbol names (start and end).")
- endif()
- endif()
- set(SECTION)
- zephyr_linker_arg_val_list(SECTION "${single_args}")
- zephyr_linker_arg_val_list(SECTION "${options}")
- zephyr_linker_arg_val_list(SECTION "${multi_args}")
- string(REPLACE ";" "\;" SECTION "${SECTION}")
- set_property(TARGET linker
- APPEND PROPERTY SECTION_SETTINGS "{${SECTION}}"
- )
- endfunction()
- # Usage:
- # zephyr_linker_symbol(SYMBOL <name> EXPR <expr>)
- #
- # Add additional user defined symbol to the generated linker script.
- #
- # SYMBOL <name>: Symbol name to be available.
- # EXPR <expr> : Expression that defines the symbol. Due to linker limitations
- # all expressions should only contain simple math, such as
- # `+, -, *` and similar. The expression will go directly into the
- # linker, and all `%<symbol>%` will be replaced with the referred
- # symbol.
- #
- # Example:
- # To create a new symbol `bar` pointing to the start VMA address of section
- # `foo` + 1024, one can write:
- # zephyr_linker_symbol(SYMBOL bar EXPR "(%foo% + 1024)")
- #
- function(zephyr_linker_symbol)
- set(single_args "EXPR;SYMBOL")
- cmake_parse_arguments(SYMBOL "" "${single_args}" "" ${ARGN})
- if(SECTION_UNPARSED_ARGUMENTS)
- message(WARNING "zephyr_linker_symbol(${ARGV0} ...) given unknown "
- "arguments: ${SECTION_UNPARSED_ARGUMENTS}"
- )
- endif()
- set(SYMBOL)
- zephyr_linker_arg_val_list(SYMBOL "${single_args}")
- string(REPLACE ";" "\;" SYMBOL "${SYMBOL}")
- set_property(TARGET linker
- APPEND PROPERTY SYMBOLS "{${SYMBOL}}"
- )
- endfunction()
- # Internal helper macro for zephyr_linker*() functions.
- # The macro will create a list of argument-value pairs for defined arguments
- # that can be passed on to linker script generators and processed as a CMake
- # function call using cmake_parse_arguments.
- #
- # For example, having the following argument and value:
- # FOO: bar
- # BAZ: <undefined>
- # QUX: option set
- #
- # will create a list as: "FOO;bar;QUX:TRUE" which can then be parsed as argument
- # list later.
- macro(zephyr_linker_arg_val_list list arguments)
- foreach(arg ${arguments})
- if(DEFINED ${list}_${arg})
- list(APPEND ${list} ${arg} "${${list}_${arg}}")
- endif()
- endforeach()
- endmacro()
|