301c0907900050d6886df75318a14f5e7634ccbc859f0ce1d794df17b9257a921837335cc14e0f27e6a013b8e5ab9909962ba42d2ee027f95dc094c89b4d4c 109 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745
  1. # Copyright (c) 2013 Google Inc. All rights reserved.
  2. # Use of this source code is governed by a BSD-style license that can be
  3. # found in the LICENSE file.
  4. # Notes:
  5. #
  6. # This is all roughly based on the Makefile system used by the Linux
  7. # kernel, but is a non-recursive make -- we put the entire dependency
  8. # graph in front of make and let it figure it out.
  9. #
  10. # The code below generates a separate .mk file for each target, but
  11. # all are sourced by the top-level Makefile. This means that all
  12. # variables in .mk-files clobber one another. Be careful to use :=
  13. # where appropriate for immediate evaluation, and similarly to watch
  14. # that you're not relying on a variable value to last between different
  15. # .mk files.
  16. #
  17. # TODOs:
  18. #
  19. # Global settings and utility functions are currently stuffed in the
  20. # toplevel Makefile. It may make sense to generate some .mk files on
  21. # the side to keep the files readable.
  22. import os
  23. import re
  24. import subprocess
  25. import sys
  26. import gyp
  27. import gyp.common
  28. import gyp.xcode_emulation
  29. from gyp.common import GetEnvironFallback
  30. import hashlib
  31. generator_default_variables = {
  32. "EXECUTABLE_PREFIX": "",
  33. "EXECUTABLE_SUFFIX": "",
  34. "STATIC_LIB_PREFIX": "lib",
  35. "SHARED_LIB_PREFIX": "lib",
  36. "STATIC_LIB_SUFFIX": ".a",
  37. "INTERMEDIATE_DIR": "$(obj).$(TOOLSET)/$(TARGET)/geni",
  38. "SHARED_INTERMEDIATE_DIR": "$(obj)/gen",
  39. "PRODUCT_DIR": "$(builddir)",
  40. "RULE_INPUT_ROOT": "%(INPUT_ROOT)s", # This gets expanded by Python.
  41. "RULE_INPUT_DIRNAME": "%(INPUT_DIRNAME)s", # This gets expanded by Python.
  42. "RULE_INPUT_PATH": "$(abspath $<)",
  43. "RULE_INPUT_EXT": "$(suffix $<)",
  44. "RULE_INPUT_NAME": "$(notdir $<)",
  45. "CONFIGURATION_NAME": "$(BUILDTYPE)",
  46. }
  47. # Make supports multiple toolsets
  48. generator_supports_multiple_toolsets = gyp.common.CrossCompileRequested()
  49. # Request sorted dependencies in the order from dependents to dependencies.
  50. generator_wants_sorted_dependencies = False
  51. # Placates pylint.
  52. generator_additional_non_configuration_keys = []
  53. generator_additional_path_sections = []
  54. generator_extra_sources_for_rules = []
  55. generator_filelist_paths = None
  56. def CalculateVariables(default_variables, params):
  57. """Calculate additional variables for use in the build (called by gyp)."""
  58. flavor = gyp.common.GetFlavor(params)
  59. if flavor == "mac":
  60. default_variables.setdefault("OS", "mac")
  61. default_variables.setdefault("SHARED_LIB_SUFFIX", ".dylib")
  62. default_variables.setdefault(
  63. "SHARED_LIB_DIR", generator_default_variables["PRODUCT_DIR"]
  64. )
  65. default_variables.setdefault(
  66. "LIB_DIR", generator_default_variables["PRODUCT_DIR"]
  67. )
  68. # Copy additional generator configuration data from Xcode, which is shared
  69. # by the Mac Make generator.
  70. import gyp.generator.xcode as xcode_generator
  71. global generator_additional_non_configuration_keys
  72. generator_additional_non_configuration_keys = getattr(
  73. xcode_generator, "generator_additional_non_configuration_keys", []
  74. )
  75. global generator_additional_path_sections
  76. generator_additional_path_sections = getattr(
  77. xcode_generator, "generator_additional_path_sections", []
  78. )
  79. global generator_extra_sources_for_rules
  80. generator_extra_sources_for_rules = getattr(
  81. xcode_generator, "generator_extra_sources_for_rules", []
  82. )
  83. COMPILABLE_EXTENSIONS.update({".m": "objc", ".mm": "objcxx"})
  84. else:
  85. operating_system = flavor
  86. if flavor == "android":
  87. operating_system = "linux" # Keep this legacy behavior for now.
  88. default_variables.setdefault("OS", operating_system)
  89. if flavor == "aix":
  90. default_variables.setdefault("SHARED_LIB_SUFFIX", ".a")
  91. elif flavor == "zos":
  92. default_variables.setdefault("SHARED_LIB_SUFFIX", ".x")
  93. COMPILABLE_EXTENSIONS.update({".pli": "pli"})
  94. else:
  95. default_variables.setdefault("SHARED_LIB_SUFFIX", ".so")
  96. default_variables.setdefault("SHARED_LIB_DIR", "$(builddir)/lib.$(TOOLSET)")
  97. default_variables.setdefault("LIB_DIR", "$(obj).$(TOOLSET)")
  98. def CalculateGeneratorInputInfo(params):
  99. """Calculate the generator specific info that gets fed to input (called by
  100. gyp)."""
  101. generator_flags = params.get("generator_flags", {})
  102. android_ndk_version = generator_flags.get("android_ndk_version", None)
  103. # Android NDK requires a strict link order.
  104. if android_ndk_version:
  105. global generator_wants_sorted_dependencies
  106. generator_wants_sorted_dependencies = True
  107. output_dir = params["options"].generator_output or params["options"].toplevel_dir
  108. builddir_name = generator_flags.get("output_dir", "out")
  109. qualified_out_dir = os.path.normpath(
  110. os.path.join(output_dir, builddir_name, "gypfiles")
  111. )
  112. global generator_filelist_paths
  113. generator_filelist_paths = {
  114. "toplevel": params["options"].toplevel_dir,
  115. "qualified_out_dir": qualified_out_dir,
  116. }
  117. # The .d checking code below uses these functions:
  118. # wildcard, sort, foreach, shell, wordlist
  119. # wildcard can handle spaces, the rest can't.
  120. # Since I could find no way to make foreach work with spaces in filenames
  121. # correctly, the .d files have spaces replaced with another character. The .d
  122. # file for
  123. # Chromium\ Framework.framework/foo
  124. # is for example
  125. # out/Release/.deps/out/Release/Chromium?Framework.framework/foo
  126. # This is the replacement character.
  127. SPACE_REPLACEMENT = "?"
  128. LINK_COMMANDS_LINUX = """\
  129. quiet_cmd_alink = AR($(TOOLSET)) $@
  130. cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
  131. quiet_cmd_alink_thin = AR($(TOOLSET)) $@
  132. cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
  133. # Due to circular dependencies between libraries :(, we wrap the
  134. # special "figure out circular dependencies" flags around the entire
  135. # input list during linking.
  136. quiet_cmd_link = LINK($(TOOLSET)) $@
  137. cmd_link = $(LINK.$(TOOLSET)) -o $@ $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,--start-group $(LD_INPUTS) $(LIBS) -Wl,--end-group
  138. # Note: this does not handle spaces in paths
  139. define xargs
  140. $(1) $(word 1,$(2))
  141. $(if $(word 2,$(2)),$(call xargs,$(1),$(wordlist 2,$(words $(2)),$(2))))
  142. endef
  143. define write-to-file
  144. @: >$(1)
  145. $(call xargs,@printf "%s\\n" >>$(1),$(2))
  146. endef
  147. OBJ_FILE_LIST := ar-file-list
  148. define create_archive
  149. rm -f $(1) $(1).$(OBJ_FILE_LIST); mkdir -p `dirname $(1)`
  150. $(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2)))
  151. $(AR.$(TOOLSET)) crs $(1) @$(1).$(OBJ_FILE_LIST)
  152. endef
  153. define create_thin_archive
  154. rm -f $(1) $(OBJ_FILE_LIST); mkdir -p `dirname $(1)`
  155. $(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2)))
  156. $(AR.$(TOOLSET)) crsT $(1) @$(1).$(OBJ_FILE_LIST)
  157. endef
  158. # We support two kinds of shared objects (.so):
  159. # 1) shared_library, which is just bundling together many dependent libraries
  160. # into a link line.
  161. # 2) loadable_module, which is generating a module intended for dlopen().
  162. #
  163. # They differ only slightly:
  164. # In the former case, we want to package all dependent code into the .so.
  165. # In the latter case, we want to package just the API exposed by the
  166. # outermost module.
  167. # This means shared_library uses --whole-archive, while loadable_module doesn't.
  168. # (Note that --whole-archive is incompatible with the --start-group used in
  169. # normal linking.)
  170. # Other shared-object link notes:
  171. # - Set SONAME to the library filename so our binaries don't reference
  172. # the local, absolute paths used on the link command-line.
  173. quiet_cmd_solink = SOLINK($(TOOLSET)) $@
  174. cmd_solink = $(LINK.$(TOOLSET)) -o $@ -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
  175. quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
  176. cmd_solink_module = $(LINK.$(TOOLSET)) -o $@ -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
  177. """ # noqa: E501
  178. LINK_COMMANDS_MAC = """\
  179. quiet_cmd_alink = LIBTOOL-STATIC $@
  180. cmd_alink = rm -f $@ && %(python)s gyp-mac-tool filter-libtool libtool $(GYP_LIBTOOLFLAGS) -static -o $@ $(filter %%.o,$^)
  181. quiet_cmd_link = LINK($(TOOLSET)) $@
  182. cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
  183. quiet_cmd_solink = SOLINK($(TOOLSET)) $@
  184. cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o "$@" $(LD_INPUTS) $(LIBS)
  185. quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
  186. cmd_solink_module = $(LINK.$(TOOLSET)) -bundle $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
  187. """ % {'python': sys.executable} # noqa: E501
  188. LINK_COMMANDS_ANDROID = """\
  189. quiet_cmd_alink = AR($(TOOLSET)) $@
  190. cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
  191. quiet_cmd_alink_thin = AR($(TOOLSET)) $@
  192. cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
  193. # Note: this does not handle spaces in paths
  194. define xargs
  195. $(1) $(word 1,$(2))
  196. $(if $(word 2,$(2)),$(call xargs,$(1),$(wordlist 2,$(words $(2)),$(2))))
  197. endef
  198. define write-to-file
  199. @: >$(1)
  200. $(call xargs,@printf "%s\\n" >>$(1),$(2))
  201. endef
  202. OBJ_FILE_LIST := ar-file-list
  203. define create_archive
  204. rm -f $(1) $(1).$(OBJ_FILE_LIST); mkdir -p `dirname $(1)`
  205. $(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2)))
  206. $(AR.$(TOOLSET)) crs $(1) @$(1).$(OBJ_FILE_LIST)
  207. endef
  208. define create_thin_archive
  209. rm -f $(1) $(OBJ_FILE_LIST); mkdir -p `dirname $(1)`
  210. $(call write-to-file,$(1).$(OBJ_FILE_LIST),$(filter %.o,$(2)))
  211. $(AR.$(TOOLSET)) crsT $(1) @$(1).$(OBJ_FILE_LIST)
  212. endef
  213. # Due to circular dependencies between libraries :(, we wrap the
  214. # special "figure out circular dependencies" flags around the entire
  215. # input list during linking.
  216. quiet_cmd_link = LINK($(TOOLSET)) $@
  217. quiet_cmd_link_host = LINK($(TOOLSET)) $@
  218. cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
  219. cmd_link_host = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
  220. # Other shared-object link notes:
  221. # - Set SONAME to the library filename so our binaries don't reference
  222. # the local, absolute paths used on the link command-line.
  223. quiet_cmd_solink = SOLINK($(TOOLSET)) $@
  224. cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
  225. quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
  226. cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
  227. quiet_cmd_solink_module_host = SOLINK_MODULE($(TOOLSET)) $@
  228. cmd_solink_module_host = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
  229. """ # noqa: E501
  230. LINK_COMMANDS_AIX = """\
  231. quiet_cmd_alink = AR($(TOOLSET)) $@
  232. cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) -X32_64 crs $@ $(filter %.o,$^)
  233. quiet_cmd_alink_thin = AR($(TOOLSET)) $@
  234. cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) -X32_64 crs $@ $(filter %.o,$^)
  235. quiet_cmd_link = LINK($(TOOLSET)) $@
  236. cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
  237. quiet_cmd_solink = SOLINK($(TOOLSET)) $@
  238. cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
  239. quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
  240. cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
  241. """ # noqa: E501
  242. LINK_COMMANDS_OS400 = """\
  243. quiet_cmd_alink = AR($(TOOLSET)) $@
  244. cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) -X64 crs $@ $(filter %.o,$^)
  245. quiet_cmd_alink_thin = AR($(TOOLSET)) $@
  246. cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) -X64 crs $@ $(filter %.o,$^)
  247. quiet_cmd_link = LINK($(TOOLSET)) $@
  248. cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
  249. quiet_cmd_solink = SOLINK($(TOOLSET)) $@
  250. cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
  251. quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
  252. cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
  253. """ # noqa: E501
  254. LINK_COMMANDS_OS390 = """\
  255. quiet_cmd_alink = AR($(TOOLSET)) $@
  256. cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
  257. quiet_cmd_alink_thin = AR($(TOOLSET)) $@
  258. cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
  259. quiet_cmd_link = LINK($(TOOLSET)) $@
  260. cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
  261. quiet_cmd_solink = SOLINK($(TOOLSET)) $@
  262. cmd_solink = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(LD_INPUTS) $(LIBS)
  263. quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
  264. cmd_solink_module = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ $(filter-out FORCE_DO_CMD, $^) $(LIBS)
  265. """ # noqa: E501
  266. # Header of toplevel Makefile.
  267. # This should go into the build tree, but it's easier to keep it here for now.
  268. SHARED_HEADER = (
  269. """\
  270. # We borrow heavily from the kernel build setup, though we are simpler since
  271. # we don't have Kconfig tweaking settings on us.
  272. # The implicit make rules have it looking for RCS files, among other things.
  273. # We instead explicitly write all the rules we care about.
  274. # It's even quicker (saves ~200ms) to pass -r on the command line.
  275. MAKEFLAGS=-r
  276. # The source directory tree.
  277. srcdir := %(srcdir)s
  278. abs_srcdir := $(abspath $(srcdir))
  279. # The name of the builddir.
  280. builddir_name ?= %(builddir)s
  281. # The V=1 flag on command line makes us verbosely print command lines.
  282. ifdef V
  283. quiet=
  284. else
  285. quiet=quiet_
  286. endif
  287. # Specify BUILDTYPE=Release on the command line for a release build.
  288. BUILDTYPE ?= %(default_configuration)s
  289. # Directory all our build output goes into.
  290. # Note that this must be two directories beneath src/ for unit tests to pass,
  291. # as they reach into the src/ directory for data with relative paths.
  292. builddir ?= $(builddir_name)/$(BUILDTYPE)
  293. abs_builddir := $(abspath $(builddir))
  294. depsdir := $(builddir)/.deps
  295. # Object output directory.
  296. obj := $(builddir)/obj
  297. abs_obj := $(abspath $(obj))
  298. # We build up a list of every single one of the targets so we can slurp in the
  299. # generated dependency rule Makefiles in one pass.
  300. all_deps :=
  301. %(make_global_settings)s
  302. CC.target ?= %(CC.target)s
  303. CFLAGS.target ?= $(CPPFLAGS) $(CFLAGS)
  304. CXX.target ?= %(CXX.target)s
  305. CXXFLAGS.target ?= $(CPPFLAGS) $(CXXFLAGS)
  306. LINK.target ?= %(LINK.target)s
  307. LDFLAGS.target ?= $(LDFLAGS)
  308. AR.target ?= %(AR.target)s
  309. PLI.target ?= %(PLI.target)s
  310. # C++ apps need to be linked with g++.
  311. LINK ?= $(CXX.target)
  312. # TODO(evan): move all cross-compilation logic to gyp-time so we don't need
  313. # to replicate this environment fallback in make as well.
  314. CC.host ?= %(CC.host)s
  315. CFLAGS.host ?= $(CPPFLAGS_host) $(CFLAGS_host)
  316. CXX.host ?= %(CXX.host)s
  317. CXXFLAGS.host ?= $(CPPFLAGS_host) $(CXXFLAGS_host)
  318. LINK.host ?= %(LINK.host)s
  319. LDFLAGS.host ?= $(LDFLAGS_host)
  320. AR.host ?= %(AR.host)s
  321. PLI.host ?= %(PLI.host)s
  322. # Define a dir function that can handle spaces.
  323. # http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
  324. # "leading spaces cannot appear in the text of the first argument as written.
  325. # These characters can be put into the argument value by variable substitution."
  326. empty :=
  327. space := $(empty) $(empty)
  328. # http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
  329. replace_spaces = $(subst $(space),"""
  330. + SPACE_REPLACEMENT
  331. + """,$1)
  332. unreplace_spaces = $(subst """
  333. + SPACE_REPLACEMENT
  334. + """,$(space),$1)
  335. dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
  336. # Flags to make gcc output dependency info. Note that you need to be
  337. # careful here to use the flags that ccache and distcc can understand.
  338. # We write to a dep file on the side first and then rename at the end
  339. # so we can't end up with a broken dep file.
  340. depfile = $(depsdir)/$(call replace_spaces,$@).d
  341. DEPFLAGS = %(makedep_args)s -MF $(depfile).raw
  342. # We have to fixup the deps output in a few ways.
  343. # (1) the file output should mention the proper .o file.
  344. # ccache or distcc lose the path to the target, so we convert a rule of
  345. # the form:
  346. # foobar.o: DEP1 DEP2
  347. # into
  348. # path/to/foobar.o: DEP1 DEP2
  349. # (2) we want missing files not to cause us to fail to build.
  350. # We want to rewrite
  351. # foobar.o: DEP1 DEP2 \\
  352. # DEP3
  353. # to
  354. # DEP1:
  355. # DEP2:
  356. # DEP3:
  357. # so if the files are missing, they're just considered phony rules.
  358. # We have to do some pretty insane escaping to get those backslashes
  359. # and dollar signs past make, the shell, and sed at the same time.
  360. # Doesn't work with spaces, but that's fine: .d files have spaces in
  361. # their names replaced with other characters."""
  362. r"""
  363. define fixup_dep
  364. # The depfile may not exist if the input file didn't have any #includes.
  365. touch $(depfile).raw
  366. # Fixup path as in (1).""" +
  367. (r"""
  368. sed -e "s|^$(notdir $@)|$@|" -re 's/\\\\([^$$])/\/\1/g' $(depfile).raw >> $(depfile)"""
  369. if sys.platform == 'win32' else r"""
  370. sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)""") +
  371. r"""
  372. # Add extra rules as in (2).
  373. # We remove slashes and replace spaces with new lines;
  374. # remove blank lines;
  375. # delete the first line and append a colon to the remaining lines.""" +
  376. ("""
  377. sed -e 's/\\\\\\\\$$//' -e 's/\\\\\\\\/\\//g' -e 'y| |\\n|' $(depfile).raw |\\"""
  378. if sys.platform == 'win32' else """
  379. sed -e 's|\\\\||' -e 'y| |\\n|' $(depfile).raw |\\""") +
  380. r"""
  381. grep -v '^$$' |\
  382. sed -e 1d -e 's|$$|:|' \
  383. >> $(depfile)
  384. rm $(depfile).raw
  385. endef
  386. """
  387. """
  388. # Command definitions:
  389. # - cmd_foo is the actual command to run;
  390. # - quiet_cmd_foo is the brief-output summary of the command.
  391. quiet_cmd_cc = CC($(TOOLSET)) $@
  392. cmd_cc = $(CC.$(TOOLSET)) -o $@ $< $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c
  393. quiet_cmd_cxx = CXX($(TOOLSET)) $@
  394. cmd_cxx = $(CXX.$(TOOLSET)) -o $@ $< $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c
  395. %(extra_commands)s
  396. quiet_cmd_touch = TOUCH $@
  397. cmd_touch = touch $@
  398. quiet_cmd_copy = COPY $@
  399. # send stderr to /dev/null to ignore messages when linking directories.
  400. cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp %(copy_archive_args)s "$<" "$@")
  401. quiet_cmd_symlink = SYMLINK $@
  402. cmd_symlink = ln -sf "$<" "$@"
  403. %(link_commands)s
  404. """ # noqa: E501
  405. r"""
  406. # Define an escape_quotes function to escape single quotes.
  407. # This allows us to handle quotes properly as long as we always use
  408. # use single quotes and escape_quotes.
  409. escape_quotes = $(subst ','\'',$(1))
  410. # This comment is here just to include a ' to unconfuse syntax highlighting.
  411. # Define an escape_vars function to escape '$' variable syntax.
  412. # This allows us to read/write command lines with shell variables (e.g.
  413. # $LD_LIBRARY_PATH), without triggering make substitution.
  414. escape_vars = $(subst $$,$$$$,$(1))
  415. # Helper that expands to a shell command to echo a string exactly as it is in
  416. # make. This uses printf instead of echo because printf's behaviour with respect
  417. # to escape sequences is more portable than echo's across different shells
  418. # (e.g., dash, bash).
  419. exact_echo = printf '%%s\n' '$(call escape_quotes,$(1))'
  420. """
  421. """
  422. # Helper to compare the command we're about to run against the command
  423. # we logged the last time we ran the command. Produces an empty
  424. # string (false) when the commands match.
  425. # Tricky point: Make has no string-equality test function.
  426. # The kernel uses the following, but it seems like it would have false
  427. # positives, where one string reordered its arguments.
  428. # arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \\
  429. # $(filter-out $(cmd_$@), $(cmd_$(1))))
  430. # We instead substitute each for the empty string into the other, and
  431. # say they're equal if both substitutions produce the empty string.
  432. # .d files contain """
  433. + SPACE_REPLACEMENT
  434. + """ instead of spaces, take that into account.
  435. command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\\
  436. $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
  437. # Helper that is non-empty when a prerequisite changes.
  438. # Normally make does this implicitly, but we force rules to always run
  439. # so we can check their command lines.
  440. # $? -- new prerequisites
  441. # $| -- order-only dependencies
  442. prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
  443. # Helper that executes all postbuilds until one fails.
  444. define do_postbuilds
  445. @E=0;\\
  446. for p in $(POSTBUILDS); do\\
  447. eval $$p;\\
  448. E=$$?;\\
  449. if [ $$E -ne 0 ]; then\\
  450. break;\\
  451. fi;\\
  452. done;\\
  453. if [ $$E -ne 0 ]; then\\
  454. rm -rf "$@";\\
  455. exit $$E;\\
  456. fi
  457. endef
  458. # do_cmd: run a command via the above cmd_foo names, if necessary.
  459. # Should always run for a given target to handle command-line changes.
  460. # Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
  461. # Third argument, if non-zero, makes it do POSTBUILDS processing.
  462. # Note: We intentionally do NOT call dirx for depfile, since it contains """
  463. + SPACE_REPLACEMENT
  464. + """ for
  465. # spaces already and dirx strips the """
  466. + SPACE_REPLACEMENT
  467. + """ characters.
  468. define do_cmd
  469. $(if $(or $(command_changed),$(prereq_changed)),
  470. @$(call exact_echo, $($(quiet)cmd_$(1)))
  471. @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
  472. $(if $(findstring flock,$(word %(flock_index)d,$(cmd_$1))),
  473. @$(cmd_$(1))
  474. @echo " $(quiet_cmd_$(1)): Finished",
  475. @$(cmd_$(1))
  476. )
  477. @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
  478. @$(if $(2),$(fixup_dep))
  479. $(if $(and $(3), $(POSTBUILDS)),
  480. $(call do_postbuilds)
  481. )
  482. )
  483. endef
  484. # Declare the "%(default_target)s" target first so it is the default,
  485. # even though we don't have the deps yet.
  486. .PHONY: %(default_target)s
  487. %(default_target)s:
  488. # make looks for ways to re-generate included makefiles, but in our case, we
  489. # don't have a direct way. Explicitly telling make that it has nothing to do
  490. # for them makes it go faster.
  491. %%.d: ;
  492. # Use FORCE_DO_CMD to force a target to run. Should be coupled with
  493. # do_cmd.
  494. .PHONY: FORCE_DO_CMD
  495. FORCE_DO_CMD:
  496. """ # noqa: E501
  497. )
  498. SHARED_HEADER_MAC_COMMANDS = """
  499. quiet_cmd_objc = CXX($(TOOLSET)) $@
  500. cmd_objc = $(CC.$(TOOLSET)) $(GYP_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
  501. quiet_cmd_objcxx = CXX($(TOOLSET)) $@
  502. cmd_objcxx = $(CXX.$(TOOLSET)) $(GYP_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
  503. # Commands for precompiled header files.
  504. quiet_cmd_pch_c = CXX($(TOOLSET)) $@
  505. cmd_pch_c = $(CC.$(TOOLSET)) $(GYP_PCH_CFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
  506. quiet_cmd_pch_cc = CXX($(TOOLSET)) $@
  507. cmd_pch_cc = $(CC.$(TOOLSET)) $(GYP_PCH_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
  508. quiet_cmd_pch_m = CXX($(TOOLSET)) $@
  509. cmd_pch_m = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCFLAGS) $(DEPFLAGS) -c -o $@ $<
  510. quiet_cmd_pch_mm = CXX($(TOOLSET)) $@
  511. cmd_pch_mm = $(CC.$(TOOLSET)) $(GYP_PCH_OBJCXXFLAGS) $(DEPFLAGS) -c -o $@ $<
  512. # gyp-mac-tool is written next to the root Makefile by gyp.
  513. # Use $(4) for the command, since $(2) and $(3) are used as flag by do_cmd
  514. # already.
  515. quiet_cmd_mac_tool = MACTOOL $(4) $<
  516. cmd_mac_tool = %(python)s gyp-mac-tool $(4) $< "$@"
  517. quiet_cmd_mac_package_framework = PACKAGE FRAMEWORK $@
  518. cmd_mac_package_framework = %(python)s gyp-mac-tool package-framework "$@" $(4)
  519. quiet_cmd_infoplist = INFOPLIST $@
  520. cmd_infoplist = $(CC.$(TOOLSET)) -E -P -Wno-trigraphs -x c $(INFOPLIST_DEFINES) "$<" -o "$@"
  521. """ % {'python': sys.executable} # noqa: E501
  522. def WriteRootHeaderSuffixRules(writer):
  523. extensions = sorted(COMPILABLE_EXTENSIONS.keys(), key=str.lower)
  524. writer.write("# Suffix rules, putting all outputs into $(obj).\n")
  525. for ext in extensions:
  526. writer.write("$(obj).$(TOOLSET)/%%.o: $(srcdir)/%%%s FORCE_DO_CMD\n" % ext)
  527. writer.write("\t@$(call do_cmd,%s,1)\n" % COMPILABLE_EXTENSIONS[ext])
  528. writer.write("\n# Try building from generated source, too.\n")
  529. for ext in extensions:
  530. writer.write(
  531. "$(obj).$(TOOLSET)/%%.o: $(obj).$(TOOLSET)/%%%s FORCE_DO_CMD\n" % ext
  532. )
  533. writer.write("\t@$(call do_cmd,%s,1)\n" % COMPILABLE_EXTENSIONS[ext])
  534. writer.write("\n")
  535. for ext in extensions:
  536. writer.write("$(obj).$(TOOLSET)/%%.o: $(obj)/%%%s FORCE_DO_CMD\n" % ext)
  537. writer.write("\t@$(call do_cmd,%s,1)\n" % COMPILABLE_EXTENSIONS[ext])
  538. writer.write("\n")
  539. SHARED_HEADER_OS390_COMMANDS = """
  540. PLIFLAGS.target ?= -qlp=64 -qlimits=extname=31 $(PLIFLAGS)
  541. PLIFLAGS.host ?= -qlp=64 -qlimits=extname=31 $(PLIFLAGS)
  542. quiet_cmd_pli = PLI($(TOOLSET)) $@
  543. cmd_pli = $(PLI.$(TOOLSET)) $(GYP_PLIFLAGS) $(PLIFLAGS.$(TOOLSET)) -c $< && \
  544. if [ -f $(notdir $@) ]; then /bin/cp $(notdir $@) $@; else true; fi
  545. """
  546. SHARED_HEADER_SUFFIX_RULES_COMMENT1 = """\
  547. # Suffix rules, putting all outputs into $(obj).
  548. """
  549. SHARED_HEADER_SUFFIX_RULES_COMMENT2 = """\
  550. # Try building from generated source, too.
  551. """
  552. SHARED_FOOTER = """\
  553. # "all" is a concatenation of the "all" targets from all the included
  554. # sub-makefiles. This is just here to clarify.
  555. all:
  556. # Add in dependency-tracking rules. $(all_deps) is the list of every single
  557. # target in our tree. Only consider the ones with .d (dependency) info:
  558. d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
  559. ifneq ($(d_files),)
  560. include $(d_files)
  561. endif
  562. """
  563. header = """\
  564. # This file is generated by gyp; do not edit.
  565. """
  566. # Maps every compilable file extension to the do_cmd that compiles it.
  567. COMPILABLE_EXTENSIONS = {
  568. ".c": "cc",
  569. ".cc": "cxx",
  570. ".cpp": "cxx",
  571. ".cxx": "cxx",
  572. ".s": "cc",
  573. ".S": "cc",
  574. }
  575. def Compilable(filename):
  576. """Return true if the file is compilable (should be in OBJS)."""
  577. return any(res for res in (filename.endswith(e) for e in COMPILABLE_EXTENSIONS))
  578. def Linkable(filename):
  579. """Return true if the file is linkable (should be on the link line)."""
  580. return filename.endswith(".o")
  581. def Target(filename):
  582. """Translate a compilable filename to its .o target."""
  583. return os.path.splitext(filename)[0] + ".o"
  584. def EscapeShellArgument(s):
  585. """Quotes an argument so that it will be interpreted literally by a POSIX
  586. shell. Taken from
  587. http://stackoverflow.com/questions/35817/whats-the-best-way-to-escape-ossystem-calls-in-python
  588. """
  589. return "'" + s.replace("'", "'\\''") + "'"
  590. def EscapeMakeVariableExpansion(s):
  591. """Make has its own variable expansion syntax using $. We must escape it for
  592. string to be interpreted literally."""
  593. return s.replace("$", "$$")
  594. def EscapeCppDefine(s):
  595. """Escapes a CPP define so that it will reach the compiler unaltered."""
  596. s = EscapeShellArgument(s)
  597. s = EscapeMakeVariableExpansion(s)
  598. # '#' characters must be escaped even embedded in a string, else Make will
  599. # treat it as the start of a comment.
  600. return s.replace("#", r"\#")
  601. def QuoteIfNecessary(string):
  602. """TODO: Should this ideally be replaced with one or more of the above
  603. functions?"""
  604. if '"' in string:
  605. string = '"' + string.replace('"', '\\"') + '"'
  606. return string
  607. def replace_sep(string):
  608. if sys.platform == 'win32':
  609. string = string.replace('\\\\', '/').replace('\\', '/')
  610. return string
  611. def StringToMakefileVariable(string):
  612. """Convert a string to a value that is acceptable as a make variable name."""
  613. return re.sub("[^a-zA-Z0-9_]", "_", string)
  614. srcdir_prefix = ""
  615. def Sourceify(path):
  616. """Convert a path to its source directory form."""
  617. if "$(" in path:
  618. return path
  619. if os.path.isabs(path):
  620. return path
  621. return srcdir_prefix + path
  622. def QuoteSpaces(s, quote=r"\ "):
  623. return s.replace(" ", quote)
  624. def SourceifyAndQuoteSpaces(path):
  625. """Convert a path to its source directory form and quote spaces."""
  626. return QuoteSpaces(Sourceify(path))
  627. # Map from qualified target to path to output.
  628. target_outputs = {}
  629. # Map from qualified target to any linkable output. A subset
  630. # of target_outputs. E.g. when mybinary depends on liba, we want to
  631. # include liba in the linker line; when otherbinary depends on
  632. # mybinary, we just want to build mybinary first.
  633. target_link_deps = {}
  634. class MakefileWriter:
  635. """MakefileWriter packages up the writing of one target-specific foobar.mk.
  636. Its only real entry point is Write(), and is mostly used for namespacing.
  637. """
  638. def __init__(self, generator_flags, flavor):
  639. self.generator_flags = generator_flags
  640. self.flavor = flavor
  641. self.suffix_rules_srcdir = {}
  642. self.suffix_rules_objdir1 = {}
  643. self.suffix_rules_objdir2 = {}
  644. # Generate suffix rules for all compilable extensions.
  645. for ext, value in COMPILABLE_EXTENSIONS.items():
  646. # Suffix rules for source folder.
  647. self.suffix_rules_srcdir.update(
  648. {
  649. ext: (
  650. """\
  651. $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(srcdir)/%%%s FORCE_DO_CMD
  652. \t@$(call do_cmd,%s,1)
  653. """
  654. % (ext, value)
  655. )
  656. }
  657. )
  658. # Suffix rules for generated source files.
  659. self.suffix_rules_objdir1.update(
  660. {
  661. ext: (
  662. """\
  663. $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj).$(TOOLSET)/%%%s FORCE_DO_CMD
  664. \t@$(call do_cmd,%s,1)
  665. """
  666. % (ext, value)
  667. )
  668. }
  669. )
  670. self.suffix_rules_objdir2.update(
  671. {
  672. ext: (
  673. """\
  674. $(obj).$(TOOLSET)/$(TARGET)/%%.o: $(obj)/%%%s FORCE_DO_CMD
  675. \t@$(call do_cmd,%s,1)
  676. """
  677. % (ext, value)
  678. )
  679. }
  680. )
  681. def Write(
  682. self, qualified_target, base_path, output_filename, spec, configs, part_of_all
  683. ):
  684. """The main entry point: writes a .mk file for a single target.
  685. Arguments:
  686. qualified_target: target we're generating
  687. base_path: path relative to source root we're building in, used to resolve
  688. target-relative paths
  689. output_filename: output .mk file name to write
  690. spec, configs: gyp info
  691. part_of_all: flag indicating this target is part of 'all'
  692. """
  693. gyp.common.EnsureDirExists(output_filename)
  694. self.fp = open(output_filename, "w")
  695. self.fp.write(header)
  696. self.qualified_target = qualified_target
  697. self.path = base_path
  698. self.target = spec["target_name"]
  699. self.type = spec["type"]
  700. self.toolset = spec["toolset"]
  701. self.is_mac_bundle = gyp.xcode_emulation.IsMacBundle(self.flavor, spec)
  702. if self.flavor == "mac":
  703. self.xcode_settings = gyp.xcode_emulation.XcodeSettings(spec)
  704. else:
  705. self.xcode_settings = None
  706. deps, link_deps = self.ComputeDeps(spec)
  707. # Some of the generation below can add extra output, sources, or
  708. # link dependencies. All of the out params of the functions that
  709. # follow use names like extra_foo.
  710. extra_outputs = []
  711. extra_sources = []
  712. extra_link_deps = []
  713. extra_mac_bundle_resources = []
  714. mac_bundle_deps = []
  715. if self.is_mac_bundle:
  716. self.output = self.ComputeMacBundleOutput(spec)
  717. self.output_binary = self.ComputeMacBundleBinaryOutput(spec)
  718. else:
  719. self.output = self.output_binary = replace_sep(self.ComputeOutput(spec))
  720. self.is_standalone_static_library = bool(
  721. spec.get("standalone_static_library", 0)
  722. )
  723. self._INSTALLABLE_TARGETS = ("executable", "loadable_module", "shared_library")
  724. if self.is_standalone_static_library or self.type in self._INSTALLABLE_TARGETS:
  725. self.alias = os.path.basename(self.output)
  726. install_path = self._InstallableTargetInstallPath()
  727. else:
  728. self.alias = self.output
  729. install_path = self.output
  730. self.WriteLn("TOOLSET := " + self.toolset)
  731. self.WriteLn("TARGET := " + self.target)
  732. # Actions must come first, since they can generate more OBJs for use below.
  733. if "actions" in spec:
  734. self.WriteActions(
  735. spec["actions"],
  736. extra_sources,
  737. extra_outputs,
  738. extra_mac_bundle_resources,
  739. part_of_all,
  740. )
  741. # Rules must be early like actions.
  742. if "rules" in spec:
  743. self.WriteRules(
  744. spec["rules"],
  745. extra_sources,
  746. extra_outputs,
  747. extra_mac_bundle_resources,
  748. part_of_all,
  749. )
  750. if "copies" in spec:
  751. self.WriteCopies(spec["copies"], extra_outputs, part_of_all)
  752. # Bundle resources.
  753. if self.is_mac_bundle:
  754. all_mac_bundle_resources = (
  755. spec.get("mac_bundle_resources", []) + extra_mac_bundle_resources
  756. )
  757. self.WriteMacBundleResources(all_mac_bundle_resources, mac_bundle_deps)
  758. self.WriteMacInfoPlist(mac_bundle_deps)
  759. # Sources.
  760. all_sources = spec.get("sources", []) + extra_sources
  761. if all_sources:
  762. self.WriteSources(
  763. configs,
  764. deps,
  765. all_sources,
  766. extra_outputs,
  767. extra_link_deps,
  768. part_of_all,
  769. gyp.xcode_emulation.MacPrefixHeader(
  770. self.xcode_settings,
  771. lambda p: Sourceify(self.Absolutify(p)),
  772. self.Pchify,
  773. ),
  774. )
  775. sources = [x for x in all_sources if Compilable(x)]
  776. if sources:
  777. self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT1)
  778. extensions = {os.path.splitext(s)[1] for s in sources}
  779. for ext in extensions:
  780. if ext in self.suffix_rules_srcdir:
  781. self.WriteLn(self.suffix_rules_srcdir[ext])
  782. self.WriteLn(SHARED_HEADER_SUFFIX_RULES_COMMENT2)
  783. for ext in extensions:
  784. if ext in self.suffix_rules_objdir1:
  785. self.WriteLn(self.suffix_rules_objdir1[ext])
  786. for ext in extensions:
  787. if ext in self.suffix_rules_objdir2:
  788. self.WriteLn(self.suffix_rules_objdir2[ext])
  789. self.WriteLn("# End of this set of suffix rules")
  790. # Add dependency from bundle to bundle binary.
  791. if self.is_mac_bundle:
  792. mac_bundle_deps.append(self.output_binary)
  793. self.WriteTarget(
  794. spec,
  795. configs,
  796. deps,
  797. extra_link_deps + link_deps,
  798. mac_bundle_deps,
  799. extra_outputs,
  800. part_of_all,
  801. )
  802. # Update global list of target outputs, used in dependency tracking.
  803. target_outputs[qualified_target] = install_path
  804. # Update global list of link dependencies.
  805. if self.type in ("static_library", "shared_library"):
  806. target_link_deps[qualified_target] = self.output_binary
  807. # Currently any versions have the same effect, but in future the behavior
  808. # could be different.
  809. if self.generator_flags.get("android_ndk_version", None):
  810. self.WriteAndroidNdkModuleRule(self.target, all_sources, link_deps)
  811. self.fp.close()
  812. def WriteSubMake(self, output_filename, makefile_path, targets, build_dir):
  813. """Write a "sub-project" Makefile.
  814. This is a small, wrapper Makefile that calls the top-level Makefile to build
  815. the targets from a single gyp file (i.e. a sub-project).
  816. Arguments:
  817. output_filename: sub-project Makefile name to write
  818. makefile_path: path to the top-level Makefile
  819. targets: list of "all" targets for this sub-project
  820. build_dir: build output directory, relative to the sub-project
  821. """
  822. gyp.common.EnsureDirExists(output_filename)
  823. self.fp = open(output_filename, "w")
  824. self.fp.write(header)
  825. # For consistency with other builders, put sub-project build output in the
  826. # sub-project dir (see test/subdirectory/gyptest-subdir-all.py).
  827. self.WriteLn(
  828. "export builddir_name ?= %s"
  829. % replace_sep(os.path.join(os.path.dirname(output_filename), build_dir))
  830. )
  831. self.WriteLn(".PHONY: all")
  832. self.WriteLn("all:")
  833. if makefile_path:
  834. makefile_path = " -C " + makefile_path
  835. self.WriteLn("\t$(MAKE){} {}".format(makefile_path, " ".join(targets)))
  836. self.fp.close()
  837. def WriteActions(
  838. self,
  839. actions,
  840. extra_sources,
  841. extra_outputs,
  842. extra_mac_bundle_resources,
  843. part_of_all,
  844. ):
  845. """Write Makefile code for any 'actions' from the gyp input.
  846. extra_sources: a list that will be filled in with newly generated source
  847. files, if any
  848. extra_outputs: a list that will be filled in with any outputs of these
  849. actions (used to make other pieces dependent on these
  850. actions)
  851. part_of_all: flag indicating this target is part of 'all'
  852. """
  853. env = self.GetSortedXcodeEnv()
  854. for action in actions:
  855. name = StringToMakefileVariable(
  856. "{}_{}".format(self.qualified_target, action["action_name"])
  857. )
  858. self.WriteLn('### Rules for action "%s":' % action["action_name"])
  859. inputs = action["inputs"]
  860. outputs = action["outputs"]
  861. # Build up a list of outputs.
  862. # Collect the output dirs we'll need.
  863. dirs = set()
  864. for out in outputs:
  865. dir = os.path.split(out)[0]
  866. if dir:
  867. dirs.add(dir)
  868. if int(action.get("process_outputs_as_sources", False)):
  869. extra_sources += outputs
  870. if int(action.get("process_outputs_as_mac_bundle_resources", False)):
  871. extra_mac_bundle_resources += outputs
  872. # Write the actual command.
  873. action_commands = action["action"]
  874. if self.flavor == "mac":
  875. action_commands = [
  876. gyp.xcode_emulation.ExpandEnvVars(command, env)
  877. for command in action_commands
  878. ]
  879. command = gyp.common.EncodePOSIXShellList(action_commands)
  880. if "message" in action:
  881. self.WriteLn(
  882. "quiet_cmd_{} = ACTION {} $@".format(name, action["message"])
  883. )
  884. else:
  885. self.WriteLn(f"quiet_cmd_{name} = ACTION {name} $@")
  886. if len(dirs) > 0:
  887. command = "mkdir -p %s" % " ".join(dirs) + "; " + command
  888. cd_action = "cd %s; " % Sourceify(self.path or ".")
  889. # command and cd_action get written to a toplevel variable called
  890. # cmd_foo. Toplevel variables can't handle things that change per
  891. # makefile like $(TARGET), so hardcode the target.
  892. command = command.replace("$(TARGET)", self.target)
  893. cd_action = cd_action.replace("$(TARGET)", self.target)
  894. # Set LD_LIBRARY_PATH in case the action runs an executable from this
  895. # build which links to shared libs from this build.
  896. # actions run on the host, so they should in theory only use host
  897. # libraries, but until everything is made cross-compile safe, also use
  898. # target libraries.
  899. # TODO(piman): when everything is cross-compile safe, remove lib.target
  900. if self.flavor in {"zos", "aix"}:
  901. self.WriteLn(
  902. "cmd_%s = LIBPATH=$(builddir)/lib.host:"
  903. "$(builddir)/lib.target:$$LIBPATH; "
  904. "export LIBPATH; "
  905. "%s%s" % (name, cd_action, command)
  906. )
  907. else:
  908. self.WriteLn(
  909. "cmd_%s = LD_LIBRARY_PATH=$(builddir)/lib.host:"
  910. "$(builddir)/lib.target:$$LD_LIBRARY_PATH; "
  911. "export LD_LIBRARY_PATH; "
  912. "%s%s" % (name, cd_action, command)
  913. )
  914. self.WriteLn()
  915. outputs = [self.Absolutify(o) for o in outputs]
  916. # The makefile rules are all relative to the top dir, but the gyp actions
  917. # are defined relative to their containing dir. This replaces the obj
  918. # variable for the action rule with an absolute version so that the output
  919. # goes in the right place.
  920. # Only write the 'obj' and 'builddir' rules for the "primary" output (:1);
  921. # it's superfluous for the "extra outputs", and this avoids accidentally
  922. # writing duplicate dummy rules for those outputs.
  923. # Same for environment.
  924. self.WriteLn("%s: obj := $(abs_obj)" % QuoteSpaces(outputs[0]))
  925. self.WriteLn("%s: builddir := $(abs_builddir)" % QuoteSpaces(outputs[0]))
  926. self.WriteSortedXcodeEnv(outputs[0], self.GetSortedXcodeEnv())
  927. for input in inputs:
  928. assert " " not in input, (
  929. "Spaces in action input filenames not supported (%s)" % input
  930. )
  931. for output in outputs:
  932. assert " " not in output, (
  933. "Spaces in action output filenames not supported (%s)" % output
  934. )
  935. # See the comment in WriteCopies about expanding env vars.
  936. outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs]
  937. inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs]
  938. self.WriteDoCmd(
  939. outputs,
  940. [Sourceify(self.Absolutify(i)) for i in inputs],
  941. part_of_all=part_of_all,
  942. command=name,
  943. )
  944. # Stuff the outputs in a variable so we can refer to them later.
  945. outputs_variable = "action_%s_outputs" % name
  946. self.WriteLn("{} := {}".format(outputs_variable, " ".join(outputs)))
  947. extra_outputs.append("$(%s)" % outputs_variable)
  948. self.WriteLn()
  949. self.WriteLn()
  950. def WriteRules(
  951. self,
  952. rules,
  953. extra_sources,
  954. extra_outputs,
  955. extra_mac_bundle_resources,
  956. part_of_all,
  957. ):
  958. """Write Makefile code for any 'rules' from the gyp input.
  959. extra_sources: a list that will be filled in with newly generated source
  960. files, if any
  961. extra_outputs: a list that will be filled in with any outputs of these
  962. rules (used to make other pieces dependent on these rules)
  963. part_of_all: flag indicating this target is part of 'all'
  964. """
  965. env = self.GetSortedXcodeEnv()
  966. for rule in rules:
  967. name = StringToMakefileVariable(
  968. "{}_{}".format(self.qualified_target, rule["rule_name"])
  969. )
  970. count = 0
  971. self.WriteLn("### Generated for rule %s:" % name)
  972. all_outputs = []
  973. for rule_source in rule.get("rule_sources", []):
  974. dirs = set()
  975. (rule_source_dirname, rule_source_basename) = os.path.split(rule_source)
  976. (rule_source_root, rule_source_ext) = os.path.splitext(
  977. rule_source_basename
  978. )
  979. outputs = [
  980. self.ExpandInputRoot(out, rule_source_root, rule_source_dirname)
  981. for out in rule["outputs"]
  982. ]
  983. for out in outputs:
  984. dir = os.path.dirname(out)
  985. if dir:
  986. dirs.add(dir)
  987. if int(rule.get("process_outputs_as_sources", False)):
  988. extra_sources += outputs
  989. if int(rule.get("process_outputs_as_mac_bundle_resources", False)):
  990. extra_mac_bundle_resources += outputs
  991. inputs = [
  992. Sourceify(self.Absolutify(i))
  993. for i in [rule_source] + rule.get("inputs", [])
  994. ]
  995. actions = ["$(call do_cmd,%s_%d)" % (name, count)]
  996. if name == "resources_grit":
  997. # HACK: This is ugly. Grit intentionally doesn't touch the
  998. # timestamp of its output file when the file doesn't change,
  999. # which is fine in hash-based dependency systems like scons
  1000. # and forge, but not kosher in the make world. After some
  1001. # discussion, hacking around it here seems like the least
  1002. # amount of pain.
  1003. actions += ["@touch --no-create $@"]
  1004. # See the comment in WriteCopies about expanding env vars.
  1005. outputs = [gyp.xcode_emulation.ExpandEnvVars(o, env) for o in outputs]
  1006. inputs = [gyp.xcode_emulation.ExpandEnvVars(i, env) for i in inputs]
  1007. outputs = [self.Absolutify(o) for o in outputs]
  1008. all_outputs += outputs
  1009. # Only write the 'obj' and 'builddir' rules for the "primary" output
  1010. # (:1); it's superfluous for the "extra outputs", and this avoids
  1011. # accidentally writing duplicate dummy rules for those outputs.
  1012. self.WriteLn("%s: obj := $(abs_obj)" % outputs[0])
  1013. self.WriteLn("%s: builddir := $(abs_builddir)" % outputs[0])
  1014. self.WriteMakeRule(
  1015. outputs, inputs, actions, command="%s_%d" % (name, count)
  1016. )
  1017. # Spaces in rule filenames are not supported, but rule variables have
  1018. # spaces in them (e.g. RULE_INPUT_PATH expands to '$(abspath $<)').
  1019. # The spaces within the variables are valid, so remove the variables
  1020. # before checking.
  1021. variables_with_spaces = re.compile(r"\$\([^ ]* \$<\)")
  1022. for output in outputs:
  1023. output = re.sub(variables_with_spaces, "", output)
  1024. assert " " not in output, (
  1025. "Spaces in rule filenames not yet supported (%s)" % output
  1026. )
  1027. self.WriteLn("all_deps += %s" % " ".join(outputs))
  1028. action = [
  1029. self.ExpandInputRoot(ac, rule_source_root, rule_source_dirname)
  1030. for ac in rule["action"]
  1031. ]
  1032. mkdirs = ""
  1033. if len(dirs) > 0:
  1034. mkdirs = "mkdir -p %s; " % " ".join(dirs)
  1035. cd_action = "cd %s; " % Sourceify(self.path or ".")
  1036. # action, cd_action, and mkdirs get written to a toplevel variable
  1037. # called cmd_foo. Toplevel variables can't handle things that change
  1038. # per makefile like $(TARGET), so hardcode the target.
  1039. if self.flavor == "mac":
  1040. action = [
  1041. gyp.xcode_emulation.ExpandEnvVars(command, env)
  1042. for command in action
  1043. ]
  1044. action = gyp.common.EncodePOSIXShellList(action)
  1045. action = action.replace("$(TARGET)", self.target)
  1046. cd_action = cd_action.replace("$(TARGET)", self.target)
  1047. mkdirs = mkdirs.replace("$(TARGET)", self.target)
  1048. # Set LD_LIBRARY_PATH in case the rule runs an executable from this
  1049. # build which links to shared libs from this build.
  1050. # rules run on the host, so they should in theory only use host
  1051. # libraries, but until everything is made cross-compile safe, also use
  1052. # target libraries.
  1053. # TODO(piman): when everything is cross-compile safe, remove lib.target
  1054. self.WriteLn(
  1055. "cmd_%(name)s_%(count)d = LD_LIBRARY_PATH="
  1056. "$(builddir)/lib.host:$(builddir)/lib.target:$$LD_LIBRARY_PATH; "
  1057. "export LD_LIBRARY_PATH; "
  1058. "%(cd_action)s%(mkdirs)s%(action)s"
  1059. % {
  1060. "action": action,
  1061. "cd_action": cd_action,
  1062. "count": count,
  1063. "mkdirs": mkdirs,
  1064. "name": name,
  1065. }
  1066. )
  1067. self.WriteLn(
  1068. "quiet_cmd_%(name)s_%(count)d = RULE %(name)s_%(count)d $@"
  1069. % {"count": count, "name": name}
  1070. )
  1071. self.WriteLn()
  1072. count += 1
  1073. outputs_variable = "rule_%s_outputs" % name
  1074. self.WriteList(all_outputs, outputs_variable)
  1075. extra_outputs.append("$(%s)" % outputs_variable)
  1076. self.WriteLn("### Finished generating for rule: %s" % name)
  1077. self.WriteLn()
  1078. self.WriteLn("### Finished generating for all rules")
  1079. self.WriteLn("")
  1080. def WriteCopies(self, copies, extra_outputs, part_of_all):
  1081. """Write Makefile code for any 'copies' from the gyp input.
  1082. extra_outputs: a list that will be filled in with any outputs of this action
  1083. (used to make other pieces dependent on this action)
  1084. part_of_all: flag indicating this target is part of 'all'
  1085. """
  1086. self.WriteLn("### Generated for copy rule.")
  1087. variable = StringToMakefileVariable(self.qualified_target + "_copies")
  1088. outputs = []
  1089. for copy in copies:
  1090. for path in copy["files"]:
  1091. # Absolutify() may call normpath, and will strip trailing slashes.
  1092. path = Sourceify(self.Absolutify(path))
  1093. filename = os.path.split(path)[1]
  1094. output = Sourceify(
  1095. self.Absolutify(os.path.join(copy["destination"], filename))
  1096. )
  1097. # If the output path has variables in it, which happens in practice for
  1098. # 'copies', writing the environment as target-local doesn't work,
  1099. # because the variables are already needed for the target name.
  1100. # Copying the environment variables into global make variables doesn't
  1101. # work either, because then the .d files will potentially contain spaces
  1102. # after variable expansion, and .d file handling cannot handle spaces.
  1103. # As a workaround, manually expand variables at gyp time. Since 'copies'
  1104. # can't run scripts, there's no need to write the env then.
  1105. # WriteDoCmd() will escape spaces for .d files.
  1106. env = self.GetSortedXcodeEnv()
  1107. output = gyp.xcode_emulation.ExpandEnvVars(output, env)
  1108. path = gyp.xcode_emulation.ExpandEnvVars(path, env)
  1109. self.WriteDoCmd([output], [path], "copy", part_of_all)
  1110. outputs.append(output)
  1111. self.WriteLn(
  1112. "{} = {}".format(variable, " ".join(QuoteSpaces(o) for o in outputs))
  1113. )
  1114. extra_outputs.append("$(%s)" % variable)
  1115. self.WriteLn()
  1116. def WriteMacBundleResources(self, resources, bundle_deps):
  1117. """Writes Makefile code for 'mac_bundle_resources'."""
  1118. self.WriteLn("### Generated for mac_bundle_resources")
  1119. for output, res in gyp.xcode_emulation.GetMacBundleResources(
  1120. generator_default_variables["PRODUCT_DIR"],
  1121. self.xcode_settings,
  1122. [Sourceify(self.Absolutify(r)) for r in resources],
  1123. ):
  1124. _, ext = os.path.splitext(output)
  1125. if ext != ".xcassets":
  1126. # Make does not supports '.xcassets' emulation.
  1127. self.WriteDoCmd(
  1128. [output], [res], "mac_tool,,,copy-bundle-resource", part_of_all=True
  1129. )
  1130. bundle_deps.append(output)
  1131. def WriteMacInfoPlist(self, bundle_deps):
  1132. """Write Makefile code for bundle Info.plist files."""
  1133. info_plist, out, defines, extra_env = gyp.xcode_emulation.GetMacInfoPlist(
  1134. generator_default_variables["PRODUCT_DIR"],
  1135. self.xcode_settings,
  1136. lambda p: Sourceify(self.Absolutify(p)),
  1137. )
  1138. if not info_plist:
  1139. return
  1140. if defines:
  1141. # Create an intermediate file to store preprocessed results.
  1142. intermediate_plist = "$(obj).$(TOOLSET)/$(TARGET)/" + os.path.basename(
  1143. info_plist
  1144. )
  1145. self.WriteList(
  1146. defines,
  1147. intermediate_plist + ": INFOPLIST_DEFINES",
  1148. "-D",
  1149. quoter=EscapeCppDefine,
  1150. )
  1151. self.WriteMakeRule(
  1152. [intermediate_plist],
  1153. [info_plist],
  1154. [
  1155. "$(call do_cmd,infoplist)",
  1156. # "Convert" the plist so that any weird whitespace changes from the
  1157. # preprocessor do not affect the XML parser in mac_tool.
  1158. "@plutil -convert xml1 $@ $@",
  1159. ],
  1160. )
  1161. info_plist = intermediate_plist
  1162. # plists can contain envvars and substitute them into the file.
  1163. self.WriteSortedXcodeEnv(
  1164. out, self.GetSortedXcodeEnv(additional_settings=extra_env)
  1165. )
  1166. self.WriteDoCmd(
  1167. [out], [info_plist], "mac_tool,,,copy-info-plist", part_of_all=True
  1168. )
  1169. bundle_deps.append(out)
  1170. def WriteSources(
  1171. self,
  1172. configs,
  1173. deps,
  1174. sources,
  1175. extra_outputs,
  1176. extra_link_deps,
  1177. part_of_all,
  1178. precompiled_header,
  1179. ):
  1180. """Write Makefile code for any 'sources' from the gyp input.
  1181. These are source files necessary to build the current target.
  1182. configs, deps, sources: input from gyp.
  1183. extra_outputs: a list of extra outputs this action should be dependent on;
  1184. used to serialize action/rules before compilation
  1185. extra_link_deps: a list that will be filled in with any outputs of
  1186. compilation (to be used in link lines)
  1187. part_of_all: flag indicating this target is part of 'all'
  1188. """
  1189. # Write configuration-specific variables for CFLAGS, etc.
  1190. for configname in sorted(configs.keys()):
  1191. config = configs[configname]
  1192. self.WriteList(
  1193. config.get("defines"),
  1194. "DEFS_%s" % configname,
  1195. prefix="-D",
  1196. quoter=EscapeCppDefine,
  1197. )
  1198. if self.flavor == "mac":
  1199. cflags = self.xcode_settings.GetCflags(
  1200. configname, arch=config.get("xcode_configuration_platform")
  1201. )
  1202. cflags_c = self.xcode_settings.GetCflagsC(configname)
  1203. cflags_cc = self.xcode_settings.GetCflagsCC(configname)
  1204. cflags_objc = self.xcode_settings.GetCflagsObjC(configname)
  1205. cflags_objcc = self.xcode_settings.GetCflagsObjCC(configname)
  1206. else:
  1207. cflags = config.get("cflags")
  1208. cflags_c = config.get("cflags_c")
  1209. cflags_cc = config.get("cflags_cc")
  1210. self.WriteLn("# Flags passed to all source files.")
  1211. self.WriteList(cflags, "CFLAGS_%s" % configname)
  1212. self.WriteLn("# Flags passed to only C files.")
  1213. self.WriteList(cflags_c, "CFLAGS_C_%s" % configname)
  1214. self.WriteLn("# Flags passed to only C++ files.")
  1215. self.WriteList(cflags_cc, "CFLAGS_CC_%s" % configname)
  1216. if self.flavor == "mac":
  1217. self.WriteLn("# Flags passed to only ObjC files.")
  1218. self.WriteList(cflags_objc, "CFLAGS_OBJC_%s" % configname)
  1219. self.WriteLn("# Flags passed to only ObjC++ files.")
  1220. self.WriteList(cflags_objcc, "CFLAGS_OBJCC_%s" % configname)
  1221. includes = config.get("include_dirs")
  1222. if includes:
  1223. includes = [Sourceify(self.Absolutify(i)) for i in includes]
  1224. self.WriteList(includes, "INCS_%s" % configname, prefix="-I")
  1225. compilable = list(filter(Compilable, sources))
  1226. objs = [self.Objectify(self.Absolutify(Target(c))) for c in compilable]
  1227. self.WriteList(objs, "OBJS")
  1228. for obj in objs:
  1229. assert " " not in obj, "Spaces in object filenames not supported (%s)" % obj
  1230. self.WriteLn(
  1231. "# Add to the list of files we specially track " "dependencies for."
  1232. )
  1233. self.WriteLn("all_deps += $(OBJS)")
  1234. self.WriteLn()
  1235. # Make sure our dependencies are built first.
  1236. if deps:
  1237. self.WriteMakeRule(
  1238. ["$(OBJS)"],
  1239. deps,
  1240. comment="Make sure our dependencies are built " "before any of us.",
  1241. order_only=True,
  1242. )
  1243. # Make sure the actions and rules run first.
  1244. # If they generate any extra headers etc., the per-.o file dep tracking
  1245. # will catch the proper rebuilds, so order only is still ok here.
  1246. if extra_outputs:
  1247. self.WriteMakeRule(
  1248. ["$(OBJS)"],
  1249. extra_outputs,
  1250. comment="Make sure our actions/rules run " "before any of us.",
  1251. order_only=True,
  1252. )
  1253. pchdeps = precompiled_header.GetObjDependencies(compilable, objs)
  1254. if pchdeps:
  1255. self.WriteLn("# Dependencies from obj files to their precompiled headers")
  1256. for source, obj, gch in pchdeps:
  1257. self.WriteLn(f"{obj}: {gch}")
  1258. self.WriteLn("# End precompiled header dependencies")
  1259. if objs:
  1260. extra_link_deps.append("$(OBJS)")
  1261. self.WriteLn(
  1262. """\
  1263. # CFLAGS et al overrides must be target-local.
  1264. # See "Target-specific Variable Values" in the GNU Make manual."""
  1265. )
  1266. self.WriteLn("$(OBJS): TOOLSET := $(TOOLSET)")
  1267. self.WriteLn(
  1268. "$(OBJS): GYP_CFLAGS := "
  1269. "$(DEFS_$(BUILDTYPE)) "
  1270. "$(INCS_$(BUILDTYPE)) "
  1271. "%s " % precompiled_header.GetInclude("c") + "$(CFLAGS_$(BUILDTYPE)) "
  1272. "$(CFLAGS_C_$(BUILDTYPE))"
  1273. )
  1274. self.WriteLn(
  1275. "$(OBJS): GYP_CXXFLAGS := "
  1276. "$(DEFS_$(BUILDTYPE)) "
  1277. "$(INCS_$(BUILDTYPE)) "
  1278. "%s " % precompiled_header.GetInclude("cc") + "$(CFLAGS_$(BUILDTYPE)) "
  1279. "$(CFLAGS_CC_$(BUILDTYPE))"
  1280. )
  1281. if self.flavor == "mac":
  1282. self.WriteLn(
  1283. "$(OBJS): GYP_OBJCFLAGS := "
  1284. "$(DEFS_$(BUILDTYPE)) "
  1285. "$(INCS_$(BUILDTYPE)) "
  1286. "%s " % precompiled_header.GetInclude("m")
  1287. + "$(CFLAGS_$(BUILDTYPE)) "
  1288. "$(CFLAGS_C_$(BUILDTYPE)) "
  1289. "$(CFLAGS_OBJC_$(BUILDTYPE))"
  1290. )
  1291. self.WriteLn(
  1292. "$(OBJS): GYP_OBJCXXFLAGS := "
  1293. "$(DEFS_$(BUILDTYPE)) "
  1294. "$(INCS_$(BUILDTYPE)) "
  1295. "%s " % precompiled_header.GetInclude("mm")
  1296. + "$(CFLAGS_$(BUILDTYPE)) "
  1297. "$(CFLAGS_CC_$(BUILDTYPE)) "
  1298. "$(CFLAGS_OBJCC_$(BUILDTYPE))"
  1299. )
  1300. self.WritePchTargets(precompiled_header.GetPchBuildCommands())
  1301. # If there are any object files in our input file list, link them into our
  1302. # output.
  1303. extra_link_deps += [source for source in sources if Linkable(source)]
  1304. self.WriteLn()
  1305. def WritePchTargets(self, pch_commands):
  1306. """Writes make rules to compile prefix headers."""
  1307. if not pch_commands:
  1308. return
  1309. for gch, lang_flag, lang, input in pch_commands:
  1310. extra_flags = {
  1311. "c": "$(CFLAGS_C_$(BUILDTYPE))",
  1312. "cc": "$(CFLAGS_CC_$(BUILDTYPE))",
  1313. "m": "$(CFLAGS_C_$(BUILDTYPE)) $(CFLAGS_OBJC_$(BUILDTYPE))",
  1314. "mm": "$(CFLAGS_CC_$(BUILDTYPE)) $(CFLAGS_OBJCC_$(BUILDTYPE))",
  1315. }[lang]
  1316. var_name = {
  1317. "c": "GYP_PCH_CFLAGS",
  1318. "cc": "GYP_PCH_CXXFLAGS",
  1319. "m": "GYP_PCH_OBJCFLAGS",
  1320. "mm": "GYP_PCH_OBJCXXFLAGS",
  1321. }[lang]
  1322. self.WriteLn(
  1323. f"{gch}: {var_name} := {lang_flag} " + "$(DEFS_$(BUILDTYPE)) "
  1324. "$(INCS_$(BUILDTYPE)) "
  1325. "$(CFLAGS_$(BUILDTYPE)) " + extra_flags
  1326. )
  1327. self.WriteLn(f"{gch}: {input} FORCE_DO_CMD")
  1328. self.WriteLn("\t@$(call do_cmd,pch_%s,1)" % lang)
  1329. self.WriteLn("")
  1330. assert " " not in gch, "Spaces in gch filenames not supported (%s)" % gch
  1331. self.WriteLn("all_deps += %s" % gch)
  1332. self.WriteLn("")
  1333. def ComputeOutputBasename(self, spec):
  1334. """Return the 'output basename' of a gyp spec.
  1335. E.g., the loadable module 'foobar' in directory 'baz' will produce
  1336. 'libfoobar.so'
  1337. """
  1338. assert not self.is_mac_bundle
  1339. if self.flavor == "mac" and self.type in (
  1340. "static_library",
  1341. "executable",
  1342. "shared_library",
  1343. "loadable_module",
  1344. ):
  1345. return self.xcode_settings.GetExecutablePath()
  1346. target = spec["target_name"]
  1347. target_prefix = ""
  1348. target_ext = ""
  1349. if self.type == "static_library":
  1350. if target[:3] == "lib":
  1351. target = target[3:]
  1352. target_prefix = "lib"
  1353. target_ext = ".a"
  1354. elif self.type in ("loadable_module", "shared_library"):
  1355. if target[:3] == "lib":
  1356. target = target[3:]
  1357. target_prefix = "lib"
  1358. if self.flavor == "aix":
  1359. target_ext = ".a"
  1360. elif self.flavor == "zos":
  1361. target_ext = ".x"
  1362. else:
  1363. target_ext = ".so"
  1364. elif self.type == "none":
  1365. target = "%s.stamp" % target
  1366. elif self.type != "executable":
  1367. print(
  1368. "ERROR: What output file should be generated?",
  1369. "type",
  1370. self.type,
  1371. "target",
  1372. target,
  1373. )
  1374. target_prefix = spec.get("product_prefix", target_prefix)
  1375. target = spec.get("product_name", target)
  1376. product_ext = spec.get("product_extension")
  1377. if product_ext:
  1378. target_ext = "." + product_ext
  1379. return target_prefix + target + target_ext
  1380. def _InstallImmediately(self):
  1381. return (
  1382. self.toolset == "target"
  1383. and self.flavor == "mac"
  1384. and self.type
  1385. in ("static_library", "executable", "shared_library", "loadable_module")
  1386. )
  1387. def ComputeOutput(self, spec):
  1388. """Return the 'output' (full output path) of a gyp spec.
  1389. E.g., the loadable module 'foobar' in directory 'baz' will produce
  1390. '$(obj)/baz/libfoobar.so'
  1391. """
  1392. assert not self.is_mac_bundle
  1393. path = os.path.join("$(obj)." + self.toolset, self.path)
  1394. if self.type == "executable" or self._InstallImmediately():
  1395. path = "$(builddir)"
  1396. path = spec.get("product_dir", path)
  1397. return os.path.join(path, self.ComputeOutputBasename(spec))
  1398. def ComputeMacBundleOutput(self, spec):
  1399. """Return the 'output' (full output path) to a bundle output directory."""
  1400. assert self.is_mac_bundle
  1401. path = generator_default_variables["PRODUCT_DIR"]
  1402. return os.path.join(path, self.xcode_settings.GetWrapperName())
  1403. def ComputeMacBundleBinaryOutput(self, spec):
  1404. """Return the 'output' (full output path) to the binary in a bundle."""
  1405. path = generator_default_variables["PRODUCT_DIR"]
  1406. return os.path.join(path, self.xcode_settings.GetExecutablePath())
  1407. def ComputeDeps(self, spec):
  1408. """Compute the dependencies of a gyp spec.
  1409. Returns a tuple (deps, link_deps), where each is a list of
  1410. filenames that will need to be put in front of make for either
  1411. building (deps) or linking (link_deps).
  1412. """
  1413. deps = []
  1414. link_deps = []
  1415. if "dependencies" in spec:
  1416. deps.extend(
  1417. [
  1418. target_outputs[dep]
  1419. for dep in spec["dependencies"]
  1420. if target_outputs[dep]
  1421. ]
  1422. )
  1423. for dep in spec["dependencies"]:
  1424. if dep in target_link_deps:
  1425. link_deps.append(target_link_deps[dep])
  1426. deps.extend(link_deps)
  1427. # TODO: It seems we need to transitively link in libraries (e.g. -lfoo)?
  1428. # This hack makes it work:
  1429. # link_deps.extend(spec.get('libraries', []))
  1430. return (gyp.common.uniquer(deps), gyp.common.uniquer(link_deps))
  1431. def GetSharedObjectFromSidedeck(self, sidedeck):
  1432. """Return the shared object files based on sidedeck"""
  1433. return re.sub(r"\.x$", ".so", sidedeck)
  1434. def GetUnversionedSidedeckFromSidedeck(self, sidedeck):
  1435. """Return the shared object files based on sidedeck"""
  1436. return re.sub(r"\.\d+\.x$", ".x", sidedeck)
  1437. def WriteDependencyOnExtraOutputs(self, target, extra_outputs):
  1438. self.WriteMakeRule(
  1439. [self.output_binary],
  1440. extra_outputs,
  1441. comment="Build our special outputs first.",
  1442. order_only=True,
  1443. )
  1444. def WriteTarget(
  1445. self, spec, configs, deps, link_deps, bundle_deps, extra_outputs, part_of_all
  1446. ):
  1447. """Write Makefile code to produce the final target of the gyp spec.
  1448. spec, configs: input from gyp.
  1449. deps, link_deps: dependency lists; see ComputeDeps()
  1450. extra_outputs: any extra outputs that our target should depend on
  1451. part_of_all: flag indicating this target is part of 'all'
  1452. """
  1453. self.WriteLn("### Rules for final target.")
  1454. if extra_outputs:
  1455. self.WriteDependencyOnExtraOutputs(self.output_binary, extra_outputs)
  1456. self.WriteMakeRule(
  1457. extra_outputs,
  1458. deps,
  1459. comment=("Preserve order dependency of " "special output on deps."),
  1460. order_only=True,
  1461. )
  1462. target_postbuilds = {}
  1463. if self.type != "none":
  1464. for configname in sorted(configs.keys()):
  1465. config = configs[configname]
  1466. if self.flavor == "mac":
  1467. ldflags = self.xcode_settings.GetLdflags(
  1468. configname,
  1469. generator_default_variables["PRODUCT_DIR"],
  1470. lambda p: Sourceify(self.Absolutify(p)),
  1471. arch=config.get("xcode_configuration_platform"),
  1472. )
  1473. # TARGET_POSTBUILDS_$(BUILDTYPE) is added to postbuilds later on.
  1474. gyp_to_build = gyp.common.InvertRelativePath(self.path)
  1475. target_postbuild = self.xcode_settings.AddImplicitPostbuilds(
  1476. configname,
  1477. QuoteSpaces(
  1478. os.path.normpath(os.path.join(gyp_to_build, self.output))
  1479. ),
  1480. QuoteSpaces(
  1481. os.path.normpath(
  1482. os.path.join(gyp_to_build, self.output_binary)
  1483. )
  1484. ),
  1485. )
  1486. if target_postbuild:
  1487. target_postbuilds[configname] = target_postbuild
  1488. else:
  1489. ldflags = config.get("ldflags", [])
  1490. # Compute an rpath for this output if needed.
  1491. if any(dep.endswith(".so") or ".so." in dep for dep in deps):
  1492. # We want to get the literal string "$ORIGIN"
  1493. # into the link command, so we need lots of escaping.
  1494. ldflags.append(r"-Wl,-rpath=\$$ORIGIN/")
  1495. ldflags.append(r"-Wl,-rpath-link=\$(builddir)/")
  1496. library_dirs = config.get("library_dirs", [])
  1497. ldflags += [("-L%s" % library_dir) for library_dir in library_dirs]
  1498. self.WriteList(ldflags, "LDFLAGS_%s" % configname)
  1499. if self.flavor == "mac":
  1500. self.WriteList(
  1501. self.xcode_settings.GetLibtoolflags(configname),
  1502. "LIBTOOLFLAGS_%s" % configname,
  1503. )
  1504. libraries = spec.get("libraries")
  1505. if libraries:
  1506. # Remove duplicate entries
  1507. libraries = gyp.common.uniquer(libraries)
  1508. if self.flavor == "mac":
  1509. libraries = self.xcode_settings.AdjustLibraries(libraries)
  1510. self.WriteList(libraries, "LIBS")
  1511. self.WriteLn(
  1512. "%s: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))"
  1513. % QuoteSpaces(self.output_binary)
  1514. )
  1515. self.WriteLn("%s: LIBS := $(LIBS)" % QuoteSpaces(self.output_binary))
  1516. if self.flavor == "mac":
  1517. self.WriteLn(
  1518. "%s: GYP_LIBTOOLFLAGS := $(LIBTOOLFLAGS_$(BUILDTYPE))"
  1519. % QuoteSpaces(self.output_binary)
  1520. )
  1521. # Postbuild actions. Like actions, but implicitly depend on the target's
  1522. # output.
  1523. postbuilds = []
  1524. if self.flavor == "mac":
  1525. if target_postbuilds:
  1526. postbuilds.append("$(TARGET_POSTBUILDS_$(BUILDTYPE))")
  1527. postbuilds.extend(gyp.xcode_emulation.GetSpecPostbuildCommands(spec))
  1528. if postbuilds:
  1529. # Envvars may be referenced by TARGET_POSTBUILDS_$(BUILDTYPE),
  1530. # so we must output its definition first, since we declare variables
  1531. # using ":=".
  1532. self.WriteSortedXcodeEnv(self.output, self.GetSortedXcodePostbuildEnv())
  1533. for configname, value in target_postbuilds.items():
  1534. self.WriteLn(
  1535. "%s: TARGET_POSTBUILDS_%s := %s"
  1536. % (
  1537. QuoteSpaces(self.output),
  1538. configname,
  1539. gyp.common.EncodePOSIXShellList(value),
  1540. )
  1541. )
  1542. # Postbuilds expect to be run in the gyp file's directory, so insert an
  1543. # implicit postbuild to cd to there.
  1544. postbuilds.insert(0, gyp.common.EncodePOSIXShellList(["cd", self.path]))
  1545. for i, postbuild in enumerate(postbuilds):
  1546. if not postbuild.startswith("$"):
  1547. postbuilds[i] = EscapeShellArgument(postbuild)
  1548. self.WriteLn("%s: builddir := $(abs_builddir)" % QuoteSpaces(self.output))
  1549. self.WriteLn(
  1550. "%s: POSTBUILDS := %s"
  1551. % (QuoteSpaces(self.output), " ".join(postbuilds))
  1552. )
  1553. # A bundle directory depends on its dependencies such as bundle resources
  1554. # and bundle binary. When all dependencies have been built, the bundle
  1555. # needs to be packaged.
  1556. if self.is_mac_bundle:
  1557. # If the framework doesn't contain a binary, then nothing depends
  1558. # on the actions -- make the framework depend on them directly too.
  1559. self.WriteDependencyOnExtraOutputs(self.output, extra_outputs)
  1560. # Bundle dependencies. Note that the code below adds actions to this
  1561. # target, so if you move these two lines, move the lines below as well.
  1562. self.WriteList([QuoteSpaces(dep) for dep in bundle_deps], "BUNDLE_DEPS")
  1563. self.WriteLn("%s: $(BUNDLE_DEPS)" % QuoteSpaces(self.output))
  1564. # After the framework is built, package it. Needs to happen before
  1565. # postbuilds, since postbuilds depend on this.
  1566. if self.type in ("shared_library", "loadable_module"):
  1567. self.WriteLn(
  1568. "\t@$(call do_cmd,mac_package_framework,,,%s)"
  1569. % self.xcode_settings.GetFrameworkVersion()
  1570. )
  1571. # Bundle postbuilds can depend on the whole bundle, so run them after
  1572. # the bundle is packaged, not already after the bundle binary is done.
  1573. if postbuilds:
  1574. self.WriteLn("\t@$(call do_postbuilds)")
  1575. postbuilds = [] # Don't write postbuilds for target's output.
  1576. # Needed by test/mac/gyptest-rebuild.py.
  1577. self.WriteLn("\t@true # No-op, used by tests")
  1578. # Since this target depends on binary and resources which are in
  1579. # nested subfolders, the framework directory will be older than
  1580. # its dependencies usually. To prevent this rule from executing
  1581. # on every build (expensive, especially with postbuilds), explicitly
  1582. # update the time on the framework directory.
  1583. self.WriteLn("\t@touch -c %s" % QuoteSpaces(self.output))
  1584. if postbuilds:
  1585. assert not self.is_mac_bundle, (
  1586. "Postbuilds for bundles should be done "
  1587. "on the bundle, not the binary (target '%s')" % self.target
  1588. )
  1589. assert "product_dir" not in spec, (
  1590. "Postbuilds do not work with " "custom product_dir"
  1591. )
  1592. if self.type == "executable":
  1593. self.WriteLn(
  1594. "%s: LD_INPUTS := %s"
  1595. % (
  1596. QuoteSpaces(self.output_binary),
  1597. " ".join(QuoteSpaces(dep) for dep in link_deps),
  1598. )
  1599. )
  1600. if self.toolset == "host" and self.flavor == "android":
  1601. self.WriteDoCmd(
  1602. [self.output_binary],
  1603. link_deps,
  1604. "link_host",
  1605. part_of_all,
  1606. postbuilds=postbuilds,
  1607. )
  1608. else:
  1609. self.WriteDoCmd(
  1610. [self.output_binary],
  1611. link_deps,
  1612. "link",
  1613. part_of_all,
  1614. postbuilds=postbuilds,
  1615. )
  1616. elif self.type == "static_library":
  1617. for link_dep in link_deps:
  1618. assert " " not in link_dep, (
  1619. "Spaces in alink input filenames not supported (%s)" % link_dep
  1620. )
  1621. if (
  1622. self.flavor not in ("mac", "openbsd", "netbsd", "win")
  1623. and not self.is_standalone_static_library
  1624. ):
  1625. if self.flavor in ("linux", "android"):
  1626. self.WriteMakeRule(
  1627. [self.output_binary],
  1628. link_deps,
  1629. actions=["$(call create_thin_archive,$@,$^)"],
  1630. )
  1631. else:
  1632. self.WriteDoCmd(
  1633. [self.output_binary],
  1634. link_deps,
  1635. "alink_thin",
  1636. part_of_all,
  1637. postbuilds=postbuilds,
  1638. )
  1639. else:
  1640. if self.flavor in ("linux", "android"):
  1641. self.WriteMakeRule(
  1642. [self.output_binary],
  1643. link_deps,
  1644. actions=["$(call create_archive,$@,$^)"],
  1645. )
  1646. else:
  1647. self.WriteDoCmd(
  1648. [self.output_binary],
  1649. link_deps,
  1650. "alink",
  1651. part_of_all,
  1652. postbuilds=postbuilds,
  1653. )
  1654. elif self.type == "shared_library":
  1655. self.WriteLn(
  1656. "%s: LD_INPUTS := %s"
  1657. % (
  1658. QuoteSpaces(self.output_binary),
  1659. " ".join(QuoteSpaces(dep) for dep in link_deps),
  1660. )
  1661. )
  1662. self.WriteDoCmd(
  1663. [self.output_binary],
  1664. link_deps,
  1665. "solink",
  1666. part_of_all,
  1667. postbuilds=postbuilds,
  1668. )
  1669. # z/OS has a .so target as well as a sidedeck .x target
  1670. if self.flavor == "zos":
  1671. self.WriteLn(
  1672. "%s: %s"
  1673. % (
  1674. QuoteSpaces(
  1675. self.GetSharedObjectFromSidedeck(self.output_binary)
  1676. ),
  1677. QuoteSpaces(self.output_binary),
  1678. )
  1679. )
  1680. elif self.type == "loadable_module":
  1681. for link_dep in link_deps:
  1682. assert " " not in link_dep, (
  1683. "Spaces in module input filenames not supported (%s)" % link_dep
  1684. )
  1685. if self.toolset == "host" and self.flavor == "android":
  1686. self.WriteDoCmd(
  1687. [self.output_binary],
  1688. link_deps,
  1689. "solink_module_host",
  1690. part_of_all,
  1691. postbuilds=postbuilds,
  1692. )
  1693. else:
  1694. self.WriteDoCmd(
  1695. [self.output_binary],
  1696. link_deps,
  1697. "solink_module",
  1698. part_of_all,
  1699. postbuilds=postbuilds,
  1700. )
  1701. elif self.type == "none":
  1702. # Write a stamp line.
  1703. self.WriteDoCmd(
  1704. [self.output_binary], deps, "touch", part_of_all, postbuilds=postbuilds
  1705. )
  1706. else:
  1707. print("WARNING: no output for", self.type, self.target)
  1708. # Add an alias for each target (if there are any outputs).
  1709. # Installable target aliases are created below.
  1710. if (self.output and self.output != self.target) and (
  1711. self.type not in self._INSTALLABLE_TARGETS
  1712. ):
  1713. self.WriteMakeRule(
  1714. [self.target], [self.output], comment="Add target alias", phony=True
  1715. )
  1716. if part_of_all:
  1717. self.WriteMakeRule(
  1718. ["all"],
  1719. [self.target],
  1720. comment='Add target alias to "all" target.',
  1721. phony=True,
  1722. )
  1723. # Add special-case rules for our installable targets.
  1724. # 1) They need to install to the build dir or "product" dir.
  1725. # 2) They get shortcuts for building (e.g. "make chrome").
  1726. # 3) They are part of "make all".
  1727. if self.type in self._INSTALLABLE_TARGETS or self.is_standalone_static_library:
  1728. if self.type == "shared_library":
  1729. file_desc = "shared library"
  1730. elif self.type == "static_library":
  1731. file_desc = "static library"
  1732. else:
  1733. file_desc = "executable"
  1734. install_path = self._InstallableTargetInstallPath()
  1735. installable_deps = []
  1736. if self.flavor != "zos":
  1737. installable_deps.append(self.output)
  1738. if (
  1739. self.flavor == "mac"
  1740. and "product_dir" not in spec
  1741. and self.toolset == "target"
  1742. ):
  1743. # On mac, products are created in install_path immediately.
  1744. assert install_path == self.output, f"{install_path} != {self.output}"
  1745. # Point the target alias to the final binary output.
  1746. self.WriteMakeRule(
  1747. [self.target], [install_path], comment="Add target alias", phony=True
  1748. )
  1749. if install_path != self.output:
  1750. assert not self.is_mac_bundle # See comment a few lines above.
  1751. self.WriteDoCmd(
  1752. [install_path],
  1753. [self.output],
  1754. "copy",
  1755. comment="Copy this to the %s output path." % file_desc,
  1756. part_of_all=part_of_all,
  1757. )
  1758. if self.flavor != "zos":
  1759. installable_deps.append(install_path)
  1760. if self.flavor == "zos" and self.type == "shared_library":
  1761. # lib.target/libnode.so has a dependency on $(obj).target/libnode.so
  1762. self.WriteDoCmd(
  1763. [self.GetSharedObjectFromSidedeck(install_path)],
  1764. [self.GetSharedObjectFromSidedeck(self.output)],
  1765. "copy",
  1766. comment="Copy this to the %s output path." % file_desc,
  1767. part_of_all=part_of_all,
  1768. )
  1769. # Create a symlink of libnode.x to libnode.version.x
  1770. self.WriteDoCmd(
  1771. [self.GetUnversionedSidedeckFromSidedeck(install_path)],
  1772. [install_path],
  1773. "symlink",
  1774. comment="Symlnk this to the %s output path." % file_desc,
  1775. part_of_all=part_of_all,
  1776. )
  1777. # Place libnode.version.so and libnode.x symlink in lib.target dir
  1778. installable_deps.append(self.GetSharedObjectFromSidedeck(install_path))
  1779. installable_deps.append(
  1780. self.GetUnversionedSidedeckFromSidedeck(install_path)
  1781. )
  1782. if self.alias not in (self.output, self.target):
  1783. self.WriteMakeRule(
  1784. [self.alias],
  1785. installable_deps,
  1786. comment="Short alias for building this %s." % file_desc,
  1787. phony=True,
  1788. )
  1789. if self.flavor == "zos" and self.type == "shared_library":
  1790. # Make sure that .x symlink target is run
  1791. self.WriteMakeRule(
  1792. ["all"],
  1793. [
  1794. self.GetUnversionedSidedeckFromSidedeck(install_path),
  1795. self.GetSharedObjectFromSidedeck(install_path),
  1796. ],
  1797. comment='Add %s to "all" target.' % file_desc,
  1798. phony=True,
  1799. )
  1800. elif part_of_all:
  1801. self.WriteMakeRule(
  1802. ["all"],
  1803. [install_path],
  1804. comment='Add %s to "all" target.' % file_desc,
  1805. phony=True,
  1806. )
  1807. def WriteList(self, value_list, variable=None, prefix="", quoter=QuoteIfNecessary):
  1808. """Write a variable definition that is a list of values.
  1809. E.g. WriteList(['a','b'], 'foo', prefix='blah') writes out
  1810. foo = blaha blahb
  1811. but in a pretty-printed style.
  1812. """
  1813. values = ""
  1814. if value_list:
  1815. value_list = [replace_sep(quoter(prefix + value)) for value in value_list]
  1816. values = " \\\n\t" + " \\\n\t".join(value_list)
  1817. self.fp.write(f"{variable} :={values}\n\n")
  1818. def WriteDoCmd(
  1819. self, outputs, inputs, command, part_of_all, comment=None, postbuilds=False
  1820. ):
  1821. """Write a Makefile rule that uses do_cmd.
  1822. This makes the outputs dependent on the command line that was run,
  1823. as well as support the V= make command line flag.
  1824. """
  1825. suffix = ""
  1826. if postbuilds:
  1827. assert "," not in command
  1828. suffix = ",,1" # Tell do_cmd to honor $POSTBUILDS
  1829. self.WriteMakeRule(
  1830. outputs,
  1831. inputs,
  1832. actions=[f"$(call do_cmd,{command}{suffix})"],
  1833. comment=comment,
  1834. command=command,
  1835. force=True,
  1836. )
  1837. # Add our outputs to the list of targets we read depfiles from.
  1838. # all_deps is only used for deps file reading, and for deps files we replace
  1839. # spaces with ? because escaping doesn't work with make's $(sort) and
  1840. # other functions.
  1841. outputs = [QuoteSpaces(o, SPACE_REPLACEMENT) for o in outputs]
  1842. self.WriteLn("all_deps += %s" % " ".join(outputs))
  1843. def WriteMakeRule(
  1844. self,
  1845. outputs,
  1846. inputs,
  1847. actions=None,
  1848. comment=None,
  1849. order_only=False,
  1850. force=False,
  1851. phony=False,
  1852. command=None,
  1853. ):
  1854. """Write a Makefile rule, with some extra tricks.
  1855. outputs: a list of outputs for the rule (note: this is not directly
  1856. supported by make; see comments below)
  1857. inputs: a list of inputs for the rule
  1858. actions: a list of shell commands to run for the rule
  1859. comment: a comment to put in the Makefile above the rule (also useful
  1860. for making this Python script's code self-documenting)
  1861. order_only: if true, makes the dependency order-only
  1862. force: if true, include FORCE_DO_CMD as an order-only dep
  1863. phony: if true, the rule does not actually generate the named output, the
  1864. output is just a name to run the rule
  1865. command: (optional) command name to generate unambiguous labels
  1866. """
  1867. outputs = [QuoteSpaces(o) for o in outputs]
  1868. inputs = [QuoteSpaces(i) for i in inputs]
  1869. if comment:
  1870. self.WriteLn("# " + comment)
  1871. if phony:
  1872. self.WriteLn(".PHONY: " + " ".join(outputs))
  1873. if actions:
  1874. self.WriteLn("%s: TOOLSET := $(TOOLSET)" % outputs[0])
  1875. force_append = " FORCE_DO_CMD" if force else ""
  1876. if order_only:
  1877. # Order only rule: Just write a simple rule.
  1878. # TODO(evanm): just make order_only a list of deps instead of this hack.
  1879. self.WriteLn(
  1880. "{}: | {}{}".format(" ".join(outputs), " ".join(inputs), force_append)
  1881. )
  1882. elif len(outputs) == 1:
  1883. # Regular rule, one output: Just write a simple rule.
  1884. self.WriteLn("{}: {}{}".format(outputs[0], " ".join(inputs), force_append))
  1885. else:
  1886. # Regular rule, more than one output: Multiple outputs are tricky in
  1887. # make. We will write three rules:
  1888. # - All outputs depend on an intermediate file.
  1889. # - Make .INTERMEDIATE depend on the intermediate.
  1890. # - The intermediate file depends on the inputs and executes the
  1891. # actual command.
  1892. # - The intermediate recipe will 'touch' the intermediate file.
  1893. # - The multi-output rule will have an do-nothing recipe.
  1894. # Hash the target name to avoid generating overlong filenames.
  1895. cmddigest = hashlib.sha1(
  1896. (command or self.target).encode("utf-8")
  1897. ).hexdigest()
  1898. intermediate = "%s.intermediate" % cmddigest
  1899. self.WriteLn("{}: {}".format(" ".join(outputs), intermediate))
  1900. self.WriteLn("\t%s" % "@:")
  1901. self.WriteLn("{}: {}".format(".INTERMEDIATE", intermediate))
  1902. self.WriteLn(
  1903. "{}: {}{}".format(intermediate, " ".join(inputs), force_append)
  1904. )
  1905. actions.insert(0, "$(call do_cmd,touch)")
  1906. if actions:
  1907. for action in actions:
  1908. self.WriteLn("\t%s" % action)
  1909. self.WriteLn()
  1910. def WriteAndroidNdkModuleRule(self, module_name, all_sources, link_deps):
  1911. """Write a set of LOCAL_XXX definitions for Android NDK.
  1912. These variable definitions will be used by Android NDK but do nothing for
  1913. non-Android applications.
  1914. Arguments:
  1915. module_name: Android NDK module name, which must be unique among all
  1916. module names.
  1917. all_sources: A list of source files (will be filtered by Compilable).
  1918. link_deps: A list of link dependencies, which must be sorted in
  1919. the order from dependencies to dependents.
  1920. """
  1921. if self.type not in ("executable", "shared_library", "static_library"):
  1922. return
  1923. self.WriteLn("# Variable definitions for Android applications")
  1924. self.WriteLn("include $(CLEAR_VARS)")
  1925. self.WriteLn("LOCAL_MODULE := " + module_name)
  1926. self.WriteLn(
  1927. "LOCAL_CFLAGS := $(CFLAGS_$(BUILDTYPE)) "
  1928. "$(DEFS_$(BUILDTYPE)) "
  1929. # LOCAL_CFLAGS is applied to both of C and C++. There is
  1930. # no way to specify $(CFLAGS_C_$(BUILDTYPE)) only for C
  1931. # sources.
  1932. "$(CFLAGS_C_$(BUILDTYPE)) "
  1933. # $(INCS_$(BUILDTYPE)) includes the prefix '-I' while
  1934. # LOCAL_C_INCLUDES does not expect it. So put it in
  1935. # LOCAL_CFLAGS.
  1936. "$(INCS_$(BUILDTYPE))"
  1937. )
  1938. # LOCAL_CXXFLAGS is obsolete and LOCAL_CPPFLAGS is preferred.
  1939. self.WriteLn("LOCAL_CPPFLAGS := $(CFLAGS_CC_$(BUILDTYPE))")
  1940. self.WriteLn("LOCAL_C_INCLUDES :=")
  1941. self.WriteLn("LOCAL_LDLIBS := $(LDFLAGS_$(BUILDTYPE)) $(LIBS)")
  1942. # Detect the C++ extension.
  1943. cpp_ext = {".cc": 0, ".cpp": 0, ".cxx": 0}
  1944. default_cpp_ext = ".cpp"
  1945. for filename in all_sources:
  1946. ext = os.path.splitext(filename)[1]
  1947. if ext in cpp_ext:
  1948. cpp_ext[ext] += 1
  1949. if cpp_ext[ext] > cpp_ext[default_cpp_ext]:
  1950. default_cpp_ext = ext
  1951. self.WriteLn("LOCAL_CPP_EXTENSION := " + default_cpp_ext)
  1952. self.WriteList(
  1953. list(map(self.Absolutify, filter(Compilable, all_sources))),
  1954. "LOCAL_SRC_FILES",
  1955. )
  1956. # Filter out those which do not match prefix and suffix and produce
  1957. # the resulting list without prefix and suffix.
  1958. def DepsToModules(deps, prefix, suffix):
  1959. modules = []
  1960. for filepath in deps:
  1961. filename = os.path.basename(filepath)
  1962. if filename.startswith(prefix) and filename.endswith(suffix):
  1963. modules.append(filename[len(prefix) : -len(suffix)])
  1964. return modules
  1965. # Retrieve the default value of 'SHARED_LIB_SUFFIX'
  1966. params = {"flavor": "linux"}
  1967. default_variables = {}
  1968. CalculateVariables(default_variables, params)
  1969. self.WriteList(
  1970. DepsToModules(
  1971. link_deps,
  1972. generator_default_variables["SHARED_LIB_PREFIX"],
  1973. default_variables["SHARED_LIB_SUFFIX"],
  1974. ),
  1975. "LOCAL_SHARED_LIBRARIES",
  1976. )
  1977. self.WriteList(
  1978. DepsToModules(
  1979. link_deps,
  1980. generator_default_variables["STATIC_LIB_PREFIX"],
  1981. generator_default_variables["STATIC_LIB_SUFFIX"],
  1982. ),
  1983. "LOCAL_STATIC_LIBRARIES",
  1984. )
  1985. if self.type == "executable":
  1986. self.WriteLn("include $(BUILD_EXECUTABLE)")
  1987. elif self.type == "shared_library":
  1988. self.WriteLn("include $(BUILD_SHARED_LIBRARY)")
  1989. elif self.type == "static_library":
  1990. self.WriteLn("include $(BUILD_STATIC_LIBRARY)")
  1991. self.WriteLn()
  1992. def WriteLn(self, text=""):
  1993. self.fp.write(text + "\n")
  1994. def GetSortedXcodeEnv(self, additional_settings=None):
  1995. return gyp.xcode_emulation.GetSortedXcodeEnv(
  1996. self.xcode_settings,
  1997. "$(abs_builddir)",
  1998. os.path.join("$(abs_srcdir)", self.path),
  1999. "$(BUILDTYPE)",
  2000. additional_settings,
  2001. )
  2002. def GetSortedXcodePostbuildEnv(self):
  2003. # CHROMIUM_STRIP_SAVE_FILE is a chromium-specific hack.
  2004. # TODO(thakis): It would be nice to have some general mechanism instead.
  2005. strip_save_file = self.xcode_settings.GetPerTargetSetting(
  2006. "CHROMIUM_STRIP_SAVE_FILE", ""
  2007. )
  2008. # Even if strip_save_file is empty, explicitly write it. Else a postbuild
  2009. # might pick up an export from an earlier target.
  2010. return self.GetSortedXcodeEnv(
  2011. additional_settings={"CHROMIUM_STRIP_SAVE_FILE": strip_save_file}
  2012. )
  2013. def WriteSortedXcodeEnv(self, target, env):
  2014. for k, v in env:
  2015. # For
  2016. # foo := a\ b
  2017. # the escaped space does the right thing. For
  2018. # export foo := a\ b
  2019. # it does not -- the backslash is written to the env as literal character.
  2020. # So don't escape spaces in |env[k]|.
  2021. self.WriteLn(f"{QuoteSpaces(target)}: export {k} := {v}")
  2022. def Objectify(self, path):
  2023. """Convert a path to its output directory form."""
  2024. if "$(" in path:
  2025. path = path.replace("$(obj)/", "$(obj).%s/$(TARGET)/" % self.toolset)
  2026. if "$(obj)" not in path:
  2027. path = f"$(obj).{self.toolset}/$(TARGET)/{path}"
  2028. return path
  2029. def Pchify(self, path, lang):
  2030. """Convert a prefix header path to its output directory form."""
  2031. path = self.Absolutify(path)
  2032. if "$(" in path:
  2033. path = path.replace(
  2034. "$(obj)/", f"$(obj).{self.toolset}/$(TARGET)/pch-{lang}"
  2035. )
  2036. return path
  2037. return f"$(obj).{self.toolset}/$(TARGET)/pch-{lang}/{path}"
  2038. def Absolutify(self, path):
  2039. """Convert a subdirectory-relative path into a base-relative path.
  2040. Skips over paths that contain variables."""
  2041. if "$(" in path:
  2042. # Don't call normpath in this case, as it might collapse the
  2043. # path too aggressively if it features '..'. However it's still
  2044. # important to strip trailing slashes.
  2045. return path.rstrip("/")
  2046. return os.path.normpath(os.path.join(self.path, path))
  2047. def ExpandInputRoot(self, template, expansion, dirname):
  2048. if "%(INPUT_ROOT)s" not in template and "%(INPUT_DIRNAME)s" not in template:
  2049. return template
  2050. path = template % {
  2051. "INPUT_ROOT": expansion,
  2052. "INPUT_DIRNAME": dirname,
  2053. }
  2054. return path
  2055. def _InstallableTargetInstallPath(self):
  2056. """Returns the location of the final output for an installable target."""
  2057. # Functionality removed for all platforms to match Xcode and hoist
  2058. # shared libraries into PRODUCT_DIR for users:
  2059. # Xcode puts shared_library results into PRODUCT_DIR, and some gyp files
  2060. # rely on this. Emulate this behavior for mac.
  2061. # if self.type == "shared_library" and (
  2062. # self.flavor != "mac" or self.toolset != "target"
  2063. # ):
  2064. # # Install all shared libs into a common directory (per toolset) for
  2065. # # convenient access with LD_LIBRARY_PATH.
  2066. # return "$(builddir)/lib.%s/%s" % (self.toolset, self.alias)
  2067. if self.flavor == "zos" and self.type == "shared_library":
  2068. return "$(builddir)/lib.%s/%s" % (self.toolset, self.alias)
  2069. return "$(builddir)/" + self.alias
  2070. def WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files):
  2071. """Write the target to regenerate the Makefile."""
  2072. options = params["options"]
  2073. build_files_args = [
  2074. gyp.common.RelativePath(filename, options.toplevel_dir)
  2075. for filename in params["build_files_arg"]
  2076. ]
  2077. gyp_binary = gyp.common.FixIfRelativePath(
  2078. params["gyp_binary"], options.toplevel_dir
  2079. )
  2080. if not gyp_binary.startswith(os.sep):
  2081. gyp_binary = os.path.join(".", gyp_binary)
  2082. root_makefile.write(
  2083. "quiet_cmd_regen_makefile = ACTION Regenerating $@\n"
  2084. "cmd_regen_makefile = cd $(srcdir); %(cmd)s\n"
  2085. "%(makefile_name)s: %(deps)s\n"
  2086. "\t$(call do_cmd,regen_makefile)\n\n"
  2087. % {
  2088. "makefile_name": makefile_name,
  2089. "deps": replace_sep(
  2090. " ".join(SourceifyAndQuoteSpaces(bf) for bf in build_files)
  2091. ),
  2092. "cmd": replace_sep(gyp.common.EncodePOSIXShellList(
  2093. [gyp_binary, "-fmake"] + gyp.RegenerateFlags(options) + build_files_args
  2094. )),
  2095. }
  2096. )
  2097. def PerformBuild(data, configurations, params):
  2098. options = params["options"]
  2099. for config in configurations:
  2100. arguments = ["make"]
  2101. if options.toplevel_dir and options.toplevel_dir != ".":
  2102. arguments += "-C", options.toplevel_dir
  2103. arguments.append("BUILDTYPE=" + config)
  2104. print(f"Building [{config}]: {arguments}")
  2105. subprocess.check_call(arguments)
  2106. def GenerateOutput(target_list, target_dicts, data, params):
  2107. options = params["options"]
  2108. flavor = gyp.common.GetFlavor(params)
  2109. generator_flags = params.get("generator_flags", {})
  2110. builddir_name = generator_flags.get("output_dir", "out")
  2111. android_ndk_version = generator_flags.get("android_ndk_version", None)
  2112. default_target = generator_flags.get("default_target", "all")
  2113. def CalculateMakefilePath(build_file, base_name):
  2114. """Determine where to write a Makefile for a given gyp file."""
  2115. # Paths in gyp files are relative to the .gyp file, but we want
  2116. # paths relative to the source root for the master makefile. Grab
  2117. # the path of the .gyp file as the base to relativize against.
  2118. # E.g. "foo/bar" when we're constructing targets for "foo/bar/baz.gyp".
  2119. base_path = gyp.common.RelativePath(os.path.dirname(build_file), options.depth)
  2120. # We write the file in the base_path directory.
  2121. output_file = os.path.join(options.depth, base_path, base_name)
  2122. if options.generator_output:
  2123. output_file = os.path.join(
  2124. options.depth, options.generator_output, base_path, base_name
  2125. )
  2126. base_path = gyp.common.RelativePath(
  2127. os.path.dirname(build_file), options.toplevel_dir
  2128. )
  2129. return base_path, output_file
  2130. # TODO: search for the first non-'Default' target. This can go
  2131. # away when we add verification that all targets have the
  2132. # necessary configurations.
  2133. default_configuration = None
  2134. toolsets = {target_dicts[target]["toolset"] for target in target_list}
  2135. for target in target_list:
  2136. spec = target_dicts[target]
  2137. if spec["default_configuration"] != "Default":
  2138. default_configuration = spec["default_configuration"]
  2139. break
  2140. if not default_configuration:
  2141. default_configuration = "Default"
  2142. srcdir = "."
  2143. makefile_name = "Makefile" + options.suffix
  2144. makefile_path = os.path.join(options.toplevel_dir, makefile_name)
  2145. if options.generator_output:
  2146. global srcdir_prefix
  2147. makefile_path = os.path.join(
  2148. options.toplevel_dir, options.generator_output, makefile_name
  2149. )
  2150. srcdir = replace_sep(gyp.common.RelativePath(srcdir, options.generator_output))
  2151. srcdir_prefix = "$(srcdir)/"
  2152. flock_command = "flock"
  2153. copy_archive_arguments = "-af"
  2154. makedep_arguments = "-MMD"
  2155. # wasm-ld doesn't support --start-group/--end-group
  2156. link_commands = LINK_COMMANDS_LINUX
  2157. if flavor in ["wasi", "wasm"]:
  2158. link_commands = link_commands.replace(' -Wl,--start-group', '').replace(
  2159. ' -Wl,--end-group', ''
  2160. )
  2161. CC_target = replace_sep(GetEnvironFallback(("CC_target", "CC"), "$(CC)"))
  2162. AR_target = replace_sep(GetEnvironFallback(("AR_target", "AR"), "$(AR)"))
  2163. CXX_target = replace_sep(GetEnvironFallback(("CXX_target", "CXX"), "$(CXX)"))
  2164. LINK_target = replace_sep(GetEnvironFallback(("LINK_target", "LINK"), "$(LINK)"))
  2165. PLI_target = replace_sep(GetEnvironFallback(("PLI_target", "PLI"), "pli"))
  2166. CC_host = replace_sep(GetEnvironFallback(("CC_host", "CC"), "gcc"))
  2167. AR_host = replace_sep(GetEnvironFallback(("AR_host", "AR"), "ar"))
  2168. CXX_host = replace_sep(GetEnvironFallback(("CXX_host", "CXX"), "g++"))
  2169. LINK_host = replace_sep(GetEnvironFallback(("LINK_host", "LINK"), "$(CXX.host)"))
  2170. PLI_host = replace_sep(GetEnvironFallback(("PLI_host", "PLI"), "pli"))
  2171. header_params = {
  2172. "default_target": default_target,
  2173. "builddir": builddir_name,
  2174. "default_configuration": default_configuration,
  2175. "flock": flock_command,
  2176. "flock_index": 1,
  2177. "link_commands": link_commands,
  2178. "extra_commands": "",
  2179. "srcdir": srcdir,
  2180. "copy_archive_args": copy_archive_arguments,
  2181. "makedep_args": makedep_arguments,
  2182. "CC.target": CC_target,
  2183. "AR.target": AR_target,
  2184. "CXX.target": CXX_target,
  2185. "LINK.target": LINK_target,
  2186. "PLI.target": PLI_target,
  2187. "CC.host": CC_host,
  2188. "AR.host": AR_host,
  2189. "CXX.host": CXX_host,
  2190. "LINK.host": LINK_host,
  2191. "PLI.host": PLI_host,
  2192. }
  2193. if flavor == "mac":
  2194. flock_command = "%s gyp-mac-tool flock" % sys.executable
  2195. header_params.update(
  2196. {
  2197. "flock": flock_command,
  2198. "flock_index": 2,
  2199. "link_commands": LINK_COMMANDS_MAC,
  2200. "extra_commands": SHARED_HEADER_MAC_COMMANDS,
  2201. }
  2202. )
  2203. elif flavor == "android":
  2204. header_params.update({"link_commands": LINK_COMMANDS_ANDROID})
  2205. elif flavor == "zos":
  2206. copy_archive_arguments = "-fPR"
  2207. CC_target = GetEnvironFallback(("CC_target", "CC"), "njsc")
  2208. makedep_arguments = "-MMD"
  2209. if CC_target == "clang":
  2210. CC_host = GetEnvironFallback(("CC_host", "CC"), "clang")
  2211. CXX_target = GetEnvironFallback(("CXX_target", "CXX"), "clang++")
  2212. CXX_host = GetEnvironFallback(("CXX_host", "CXX"), "clang++")
  2213. elif CC_target == "ibm-clang64":
  2214. CC_host = GetEnvironFallback(("CC_host", "CC"), "ibm-clang64")
  2215. CXX_target = GetEnvironFallback(("CXX_target", "CXX"), "ibm-clang++64")
  2216. CXX_host = GetEnvironFallback(("CXX_host", "CXX"), "ibm-clang++64")
  2217. elif CC_target == "ibm-clang":
  2218. CC_host = GetEnvironFallback(("CC_host", "CC"), "ibm-clang")
  2219. CXX_target = GetEnvironFallback(("CXX_target", "CXX"), "ibm-clang++")
  2220. CXX_host = GetEnvironFallback(("CXX_host", "CXX"), "ibm-clang++")
  2221. else:
  2222. # Node.js versions prior to v18:
  2223. makedep_arguments = "-qmakedep=gcc"
  2224. CC_host = GetEnvironFallback(("CC_host", "CC"), "njsc")
  2225. CXX_target = GetEnvironFallback(("CXX_target", "CXX"), "njsc++")
  2226. CXX_host = GetEnvironFallback(("CXX_host", "CXX"), "njsc++")
  2227. header_params.update(
  2228. {
  2229. "copy_archive_args": copy_archive_arguments,
  2230. "makedep_args": makedep_arguments,
  2231. "link_commands": LINK_COMMANDS_OS390,
  2232. "extra_commands": SHARED_HEADER_OS390_COMMANDS,
  2233. "CC.target": CC_target,
  2234. "CXX.target": CXX_target,
  2235. "CC.host": CC_host,
  2236. "CXX.host": CXX_host,
  2237. }
  2238. )
  2239. elif flavor == "solaris":
  2240. copy_archive_arguments = "-pPRf@"
  2241. header_params.update(
  2242. {
  2243. "copy_archive_args": copy_archive_arguments,
  2244. "flock": "%s gyp-flock-tool flock" % sys.executable,
  2245. "flock_index": 2,
  2246. }
  2247. )
  2248. elif flavor == "freebsd":
  2249. # Note: OpenBSD has sysutils/flock. lockf seems to be FreeBSD specific.
  2250. header_params.update({"flock": "lockf"})
  2251. elif flavor == "openbsd":
  2252. copy_archive_arguments = "-pPRf"
  2253. header_params.update({"copy_archive_args": copy_archive_arguments})
  2254. elif flavor == "aix":
  2255. copy_archive_arguments = "-pPRf"
  2256. header_params.update(
  2257. {
  2258. "copy_archive_args": copy_archive_arguments,
  2259. "link_commands": LINK_COMMANDS_AIX,
  2260. "flock": "%s gyp-flock-tool flock" % sys.executable,
  2261. "flock_index": 2,
  2262. }
  2263. )
  2264. elif flavor == "os400":
  2265. copy_archive_arguments = "-pPRf"
  2266. header_params.update(
  2267. {
  2268. "copy_archive_args": copy_archive_arguments,
  2269. "link_commands": LINK_COMMANDS_OS400,
  2270. "flock": "%s gyp-flock-tool flock" % sys.executable,
  2271. "flock_index": 2,
  2272. }
  2273. )
  2274. build_file, _, _ = gyp.common.ParseQualifiedTarget(target_list[0])
  2275. make_global_settings_array = data[build_file].get("make_global_settings", [])
  2276. wrappers = {}
  2277. for key, value in make_global_settings_array:
  2278. if key.endswith("_wrapper"):
  2279. wrappers[key[: -len("_wrapper")]] = "$(abspath %s)" % value
  2280. make_global_settings = ""
  2281. for key, value in make_global_settings_array:
  2282. if re.match(".*_wrapper", key):
  2283. continue
  2284. if value[0] != "$":
  2285. value = "$(abspath %s)" % value
  2286. wrapper = wrappers.get(key)
  2287. if wrapper:
  2288. value = f"{wrapper} {value}"
  2289. del wrappers[key]
  2290. if key in ("CC", "CC.host", "CXX", "CXX.host"):
  2291. make_global_settings += (
  2292. "ifneq (,$(filter $(origin %s), undefined default))\n" % key
  2293. )
  2294. # Let gyp-time envvars win over global settings.
  2295. env_key = key.replace(".", "_") # CC.host -> CC_host
  2296. if env_key in os.environ:
  2297. value = os.environ[env_key]
  2298. make_global_settings += f" {key} = {value}\n"
  2299. make_global_settings += "endif\n"
  2300. else:
  2301. make_global_settings += f"{key} ?= {value}\n"
  2302. # TODO(ukai): define cmd when only wrapper is specified in
  2303. # make_global_settings.
  2304. header_params["make_global_settings"] = make_global_settings
  2305. gyp.common.EnsureDirExists(makefile_path)
  2306. root_makefile = open(makefile_path, "w")
  2307. root_makefile.write(SHARED_HEADER % header_params)
  2308. # Currently any versions have the same effect, but in future the behavior
  2309. # could be different.
  2310. if android_ndk_version:
  2311. root_makefile.write(
  2312. "# Define LOCAL_PATH for build of Android applications.\n"
  2313. "LOCAL_PATH := $(call my-dir)\n"
  2314. "\n"
  2315. )
  2316. for toolset in toolsets:
  2317. root_makefile.write("TOOLSET := %s\n" % toolset)
  2318. WriteRootHeaderSuffixRules(root_makefile)
  2319. # Put build-time support tools next to the root Makefile.
  2320. dest_path = os.path.dirname(makefile_path)
  2321. gyp.common.CopyTool(flavor, dest_path)
  2322. # Find the list of targets that derive from the gyp file(s) being built.
  2323. needed_targets = set()
  2324. for build_file in params["build_files"]:
  2325. for target in gyp.common.AllTargets(target_list, target_dicts, build_file):
  2326. needed_targets.add(target)
  2327. build_files = set()
  2328. include_list = set()
  2329. for qualified_target in target_list:
  2330. build_file, target, toolset = gyp.common.ParseQualifiedTarget(qualified_target)
  2331. this_make_global_settings = data[build_file].get("make_global_settings", [])
  2332. assert make_global_settings_array == this_make_global_settings, (
  2333. "make_global_settings needs to be the same for all targets "
  2334. f"{this_make_global_settings} vs. {make_global_settings}"
  2335. )
  2336. build_files.add(gyp.common.RelativePath(build_file, options.toplevel_dir))
  2337. included_files = data[build_file]["included_files"]
  2338. for included_file in included_files:
  2339. # The included_files entries are relative to the dir of the build file
  2340. # that included them, so we have to undo that and then make them relative
  2341. # to the root dir.
  2342. relative_include_file = gyp.common.RelativePath(
  2343. gyp.common.UnrelativePath(included_file, build_file),
  2344. options.toplevel_dir,
  2345. )
  2346. abs_include_file = os.path.abspath(relative_include_file)
  2347. # If the include file is from the ~/.gyp dir, we should use absolute path
  2348. # so that relocating the src dir doesn't break the path.
  2349. if params["home_dot_gyp"] and abs_include_file.startswith(
  2350. params["home_dot_gyp"]
  2351. ):
  2352. build_files.add(abs_include_file)
  2353. else:
  2354. build_files.add(relative_include_file)
  2355. base_path, output_file = CalculateMakefilePath(
  2356. build_file, target + "." + toolset + options.suffix + ".mk"
  2357. )
  2358. spec = target_dicts[qualified_target]
  2359. configs = spec["configurations"]
  2360. if flavor == "mac":
  2361. gyp.xcode_emulation.MergeGlobalXcodeSettingsToSpec(data[build_file], spec)
  2362. writer = MakefileWriter(generator_flags, flavor)
  2363. writer.Write(
  2364. qualified_target,
  2365. base_path,
  2366. output_file,
  2367. spec,
  2368. configs,
  2369. part_of_all=qualified_target in needed_targets,
  2370. )
  2371. # Our root_makefile lives at the source root. Compute the relative path
  2372. # from there to the output_file for including.
  2373. mkfile_rel_path = gyp.common.RelativePath(
  2374. output_file, os.path.dirname(makefile_path)
  2375. )
  2376. include_list.add(mkfile_rel_path)
  2377. # Write out per-gyp (sub-project) Makefiles.
  2378. depth_rel_path = gyp.common.RelativePath(options.depth, os.getcwd())
  2379. for build_file in build_files:
  2380. # The paths in build_files were relativized above, so undo that before
  2381. # testing against the non-relativized items in target_list and before
  2382. # calculating the Makefile path.
  2383. build_file = os.path.join(depth_rel_path, build_file)
  2384. gyp_targets = [
  2385. target_dicts[qualified_target]["target_name"]
  2386. for qualified_target in target_list
  2387. if qualified_target.startswith(build_file)
  2388. and qualified_target in needed_targets
  2389. ]
  2390. # Only generate Makefiles for gyp files with targets.
  2391. if not gyp_targets:
  2392. continue
  2393. base_path, output_file = CalculateMakefilePath(
  2394. build_file, os.path.splitext(os.path.basename(build_file))[0] + ".Makefile"
  2395. )
  2396. makefile_rel_path = gyp.common.RelativePath(
  2397. os.path.dirname(makefile_path), os.path.dirname(output_file)
  2398. )
  2399. writer.WriteSubMake(output_file, makefile_rel_path, gyp_targets, builddir_name)
  2400. # Write out the sorted list of includes.
  2401. root_makefile.write("\n")
  2402. for include_file in sorted(include_list):
  2403. # We wrap each .mk include in an if statement so users can tell make to
  2404. # not load a file by setting NO_LOAD. The below make code says, only
  2405. # load the .mk file if the .mk filename doesn't start with a token in
  2406. # NO_LOAD.
  2407. root_makefile.write(
  2408. "ifeq ($(strip $(foreach prefix,$(NO_LOAD),\\\n"
  2409. " $(findstring $(join ^,$(prefix)),\\\n"
  2410. " $(join ^," + include_file + ")))),)\n"
  2411. )
  2412. root_makefile.write(" include " + include_file + "\n")
  2413. root_makefile.write("endif\n")
  2414. root_makefile.write("\n")
  2415. if not generator_flags.get("standalone") and generator_flags.get(
  2416. "auto_regeneration", True
  2417. ):
  2418. WriteAutoRegenerationRule(params, root_makefile, makefile_name, build_files)
  2419. root_makefile.write(SHARED_FOOTER)
  2420. root_makefile.close()