1515import subprocess
1616import sys
1717import typing
18+ from shlex import quote as shellquote
1819from typing import Optional
1920
21+ from .copytree import simple_copytree
2022from .dyndeps import create_dyn_dep_munger
2123from .envfuncs import add_path_entry , Env , path_search
2224from .fetcher import copy_if_different
@@ -157,6 +159,29 @@ def debug(self, reconfigure: bool) -> None:
157159 shell = ["powershell.exe" ] if sys .platform == "win32" else ["/bin/sh" , "-i" ]
158160 self ._run_cmd (shell , cwd = self .build_dir , env = env )
159161
162+ def printenv (self , reconfigure : bool ) -> None :
163+ """print the environment in a shell sourcable format"""
164+ reconfigure = self ._reconfigure (reconfigure )
165+ self ._apply_patchfile ()
166+ self ._prepare (reconfigure = reconfigure )
167+ env = self ._compute_env (env = Env (src = {}))
168+ prefix = "export "
169+ sep = ":"
170+ expand = "$"
171+ expandpost = ""
172+ if self .build_opts .is_windows ():
173+ prefix = "SET "
174+ sep = ";"
175+ expand = "%"
176+ expandpost = "%"
177+ for k , v in sorted (env .items ()):
178+ existing = os .environ .get (k , None )
179+ if k .endswith ("PATH" ) and existing :
180+ v = shellquote (v ) + sep + f"{ expand } { k } { expandpost } "
181+ else :
182+ v = shellquote (v )
183+ print ("%s%s=%s" % (prefix , k , v ))
184+
160185 def build (self , reconfigure : bool ) -> None :
161186 print ("Building %s..." % self .manifest .name )
162187 reconfigure = self ._reconfigure (reconfigure )
@@ -225,14 +250,16 @@ def _build(self, reconfigure) -> None:
225250 system needs to regenerate its rules."""
226251 pass
227252
228- def _compute_env (self ):
253+ def _compute_env (self , env = None ) -> Env :
254+ if env is None :
255+ env = self .env
229256 # CMAKE_PREFIX_PATH is only respected when passed through the
230257 # environment, so we construct an appropriate path to pass down
231258 return self .build_opts .compute_env_for_install_dirs (
232259 self .loader ,
233260 self .dep_manifests ,
234261 self .ctx ,
235- env = self . env ,
262+ env = env ,
236263 manifest = self .manifest ,
237264 )
238265
@@ -461,6 +488,61 @@ def _build(self, reconfigure) -> None:
461488 self ._run_cmd (install_cmd , env = env )
462489
463490
491+ class SystemdBuilder (BuilderBase ):
492+ # SystemdBuilder assumes that meson build tool has already been installed on
493+ # the machine.
494+ def __init__ (
495+ self ,
496+ loader ,
497+ dep_manifests ,
498+ build_opts ,
499+ ctx ,
500+ manifest ,
501+ src_dir ,
502+ build_dir ,
503+ inst_dir ,
504+ ) -> None :
505+ super (SystemdBuilder , self ).__init__ (
506+ loader ,
507+ dep_manifests ,
508+ build_opts ,
509+ ctx ,
510+ manifest ,
511+ src_dir ,
512+ build_dir ,
513+ inst_dir ,
514+ )
515+
516+ def _build (self , reconfigure ) -> None :
517+ env = self ._compute_env ()
518+ meson = path_search (env , "meson" )
519+ if meson is None :
520+ raise Exception ("Failed to find Meson" )
521+
522+ # Meson builds typically require setup, compile, and install steps.
523+ # During this setup step we ensure that the static library is built and
524+ # the prefix is empty.
525+ self ._run_cmd (
526+ [
527+ meson ,
528+ "setup" ,
529+ "-Dstatic-libsystemd=true" ,
530+ "-Dprefix=/" ,
531+ self .build_dir ,
532+ self .src_dir ,
533+ ]
534+ )
535+
536+ # Compile step needs to satisfy the build directory that was previously
537+ # prepared during setup.
538+ self ._run_cmd ([meson , "compile" , "-C" , self .build_dir ])
539+
540+ # Install step
541+ self ._run_cmd (
542+ [meson , "install" , "-C" , self .build_dir , "--destdir" , self .inst_dir ]
543+ )
544+
545+
464546class CMakeBuilder (BuilderBase ):
465547 MANUAL_BUILD_SCRIPT = """\
466548 #!{sys.executable}
@@ -1084,9 +1166,14 @@ def _build(self, reconfigure) -> None:
10841166 perl = typing .cast (str , path_search (env , "perl" , "perl" ))
10851167
10861168 make_j_args = []
1169+ extra_args = []
10871170 if self .build_opts .is_windows ():
1088- make = "nmake.exe"
1171+ # jom is compatible with nmake, adds the /j argument for parallel build
1172+ make = "jom.exe"
1173+ make_j_args = ["/j%s" % self .num_jobs ]
10891174 args = ["VC-WIN64A-masm" , "-utf-8" ]
1175+ # fixes "if multiple CL.EXE write to the same .PDB file, please use /FS"
1176+ extra_args = ["/FS" ]
10901177 elif self .build_opts .is_darwin ():
10911178 make = "make"
10921179 make_j_args = ["-j%s" % self .num_jobs ]
@@ -1119,11 +1206,14 @@ def _build(self, reconfigure) -> None:
11191206 "no-unit-test" ,
11201207 "no-tests" ,
11211208 ]
1209+ + extra_args
11221210 )
1211+ # show the config produced
1212+ self ._run_cmd ([perl , "configdata.pm" , "--dump" ], env = env )
11231213 make_build = [make ] + make_j_args
1124- self ._run_cmd (make_build )
1214+ self ._run_cmd (make_build , env = env )
11251215 make_install = [make , "install_sw" , "install_ssldirs" ]
1126- self ._run_cmd (make_install )
1216+ self ._run_cmd (make_install , env = env )
11271217
11281218
11291219class Boost (BuilderBase ):
@@ -1240,7 +1330,7 @@ def build(self, reconfigure: bool) -> None:
12401330 os .makedirs (dest_parent )
12411331 if os .path .isdir (full_src ):
12421332 if not os .path .exists (full_dest ):
1243- shutil . copytree (full_src , full_dest )
1333+ simple_copytree (full_src , full_dest )
12441334 else :
12451335 shutil .copyfile (full_src , full_dest )
12461336 shutil .copymode (full_src , full_dest )
@@ -1252,7 +1342,7 @@ def build(self, reconfigure: bool) -> None:
12521342 os .chmod (full_dest , st .st_mode | stat .S_IXUSR )
12531343 else :
12541344 if not os .path .exists (self .inst_dir ):
1255- shutil . copytree (self .src_dir , self .inst_dir )
1345+ simple_copytree (self .src_dir , self .inst_dir )
12561346
12571347
12581348class SqliteBuilder (BuilderBase ):
0 commit comments