11 if sys
.platform
== "win32":
12 # This module was renamed in Python 3. Make sure to import it using a
13 # consistent name regardless of python version.
17 import _winreg
as winreg
19 if __name__
!= "__main__":
20 raise RuntimeError("Do not import this script, run it instead")
23 parser
= argparse
.ArgumentParser(description
="LLDB compilation wrapper")
30 choices
=["32", "64", "host"],
31 help="Specify the architecture to target.",
39 help="Path to a compiler executable, or one of the values [any, msvc, clang-cl, gcc, clang]",
48 help="If specified, a path to linked libraries to be passed via -L",
57 help="If specified, a path to search in addition to PATH when --compiler is not an exact path",
63 dest
="objc_gnustep_dir",
65 help="If specified, a path to GNUstep libobjc2 runtime for use on Windows and Linux",
73 help="Include and link GNUstep libobjc2 (Windows and Linux only)",
81 help="If specified, a sysroot to be passed via --sysroot",
84 if sys
.platform
== "darwin":
90 help="Specify the name of the Apple SDK (macosx, macosx.internal, iphoneos, iphoneos.internal, or path to SDK) and use the appropriate tools from that SDK's toolchain.",
100 help="Path to output file",
109 help="Directory for output files",
117 help="When specified, the resulting image should not link against system libraries or include system headers. Useful when writing cross-targeting tests.",
124 choices
=["none", "basic", "lto"],
125 help="Optimization level",
131 default
="compile-and-link",
132 choices
=["compile", "link", "compile-and-link"],
133 help="Specifies whether to compile, link, or both",
139 action
="store_false",
141 help="Dont clean output file before building",
149 help="Print verbose output",
158 help="Print the commands that would run, but dont actually run them",
165 help="Source file(s) to compile / object file(s) to link",
173 help="Specify the C/C++ standard.",
177 args
= parser
.parse_args(args
=sys
.argv
[1:])
181 """Return the parameter as type 'str', possibly encoding it.
183 In Python2, the 'str' type is the same as 'bytes'. In Python3, the
184 'str' type is (essentially) Python2's 'unicode' type, and 'bytes' is
187 This function is copied from llvm/utils/lit/lit/util.py
189 if isinstance(b
, str):
190 # In Python2, this branch is taken for types 'str' and 'bytes'.
191 # In Python3, this branch is taken only for 'str'.
193 if isinstance(b
, bytes
):
194 # In Python2, this branch is never taken ('bytes' is handled as 'str').
195 # In Python3, this is true only for 'bytes'.
197 return b
.decode("utf-8")
198 except UnicodeDecodeError:
199 # If the value is not valid Unicode, return the default
200 # repr-line encoding.
203 # By this point, here's what we *don't* have:
206 # - 'str' or 'bytes' (1st branch above)
208 # - 'str' (1st branch above)
209 # - 'bytes' (2nd branch above)
211 # The last type we might expect is the Python2 'unicode' type. There is no
212 # 'unicode' type in Python3 (all the Python3 cases were already handled). In
213 # order to get a 'str' object, we need to encode the 'unicode' object.
215 return b
.encode("utf-8")
216 except AttributeError:
217 raise TypeError("not sure how to convert %s to %s" % (type(b
), str))
220 def format_text(lines
, indent_0
, indent_n
):
221 result
= " " * indent_0
+ lines
[0]
222 for next
in lines
[1:]:
223 result
= result
+ "\n{0}{1}".format(" " * indent_n
, next
)
227 def print_environment(env
):
233 lines
= value
.split(os
.pathsep
)
234 formatted_value
= format_text(lines
, 0, 7 + len(e
))
235 print(" {0} = {1}".format(e
, formatted_value
))
238 def find_executable(binary_name
, search_paths
):
239 # shutil.which will ignore PATH if given a path argument, we want to include it.
240 search_paths
.append(os
.environ
.get("PATH", ""))
241 search_path
= os
.pathsep
.join(search_paths
)
242 binary_path
= shutil
.which(binary_name
, path
=search_path
)
243 if binary_path
is not None:
244 # So for example, we get '/bin/gcc' instead of '/usr/../bin/gcc'.
245 binary_path
= os
.path
.normpath(binary_path
)
249 def find_toolchain(compiler
, tools_dir
):
250 if compiler
== "msvc":
251 return ("msvc", find_executable("cl", tools_dir
))
252 if compiler
== "clang-cl":
253 return ("clang-cl", find_executable("clang-cl", tools_dir
))
254 if compiler
== "gcc":
255 return ("gcc", find_executable("g++", tools_dir
))
256 if compiler
== "clang":
257 return ("clang", find_executable("clang++", tools_dir
))
258 if compiler
== "any":
260 if sys
.platform
== "win32":
261 priorities
= ["clang-cl", "msvc", "clang", "gcc"]
263 priorities
= ["clang", "gcc", "clang-cl"]
264 for toolchain
in priorities
:
265 (type, dir) = find_toolchain(toolchain
, tools_dir
)
268 # Could not find any toolchain.
271 # From here on, assume that |compiler| is a path to a file.
272 file = os
.path
.basename(compiler
)
273 name
, ext
= os
.path
.splitext(file)
274 if file.lower() == "cl.exe":
275 return ("msvc", compiler
)
276 if name
== "clang-cl":
277 return ("clang-cl", compiler
)
278 if name
.startswith("clang"):
279 return ("clang", compiler
)
280 if name
.startswith("gcc") or name
.startswith("g++"):
281 return ("gcc", compiler
)
282 if name
== "cc" or name
== "c++":
283 return ("generic", compiler
)
284 return ("unknown", compiler
)
287 class Builder(object):
288 def __init__(self
, toolchain_type
, args
, obj_ext
):
289 self
.toolchain_type
= toolchain_type
290 self
.inputs
= args
.inputs
291 self
.arch
= args
.arch
293 self
.outdir
= args
.outdir
294 self
.compiler
= args
.compiler
295 self
.clean
= args
.clean
296 self
.output
= args
.output
297 self
.mode
= args
.mode
298 self
.nodefaultlib
= args
.nodefaultlib
299 self
.verbose
= args
.verbose
300 self
.obj_ext
= obj_ext
301 self
.lib_paths
= args
.libs_dir
304 not args
.objc_gnustep
or args
.objc_gnustep_dir
305 ), "--objc-gnustep specified without path to libobjc2"
306 self
.objc_gnustep_inc
= (
307 os
.path
.join(args
.objc_gnustep_dir
, "include")
308 if args
.objc_gnustep_dir
311 self
.objc_gnustep_lib
= (
312 os
.path
.join(args
.objc_gnustep_dir
, "lib")
313 if args
.objc_gnustep_dir
316 self
.sysroot
= args
.sysroot
318 def _exe_file_name(self
):
319 assert self
.mode
!= "compile"
322 def _output_name(self
, input, extension
, with_executable
=False):
323 basename
= os
.path
.splitext(os
.path
.basename(input))[0] + extension
325 exe_basename
= os
.path
.basename(self
._exe
_file
_name
())
326 basename
= exe_basename
+ "-" + basename
328 output
= os
.path
.join(self
.outdir
, basename
)
329 return os
.path
.normpath(output
)
331 def _obj_file_names(self
):
332 if self
.mode
== "link":
335 if self
.mode
== "compile-and-link":
336 # Object file names should factor in both the input file (source)
337 # name and output file (executable) name, to ensure that two tests
338 # which share a common source file don't race to write the same
340 return [self
._output
_name
(x
, self
.obj_ext
, True) for x
in self
.inputs
]
342 if self
.mode
== "compile" and self
.output
:
345 return [self
._output
_name
(x
, self
.obj_ext
) for x
in self
.inputs
]
347 def build_commands(self
):
349 if self
.mode
== "compile" or self
.mode
== "compile-and-link":
350 for input, output
in zip(self
.inputs
, self
._obj
_file
_names
()):
351 commands
.append(self
._get
_compilation
_command
(input, output
))
352 if self
.mode
== "link" or self
.mode
== "compile-and-link":
353 commands
.append(self
._get
_link
_command
())
357 class MsvcBuilder(Builder
):
358 def __init__(self
, toolchain_type
, args
):
359 Builder
.__init
__(self
, toolchain_type
, args
, ".obj")
361 if platform
.uname().machine
.lower() == "arm64":
362 self
.msvc_arch_str
= "arm" if self
.arch
== "32" else "arm64"
364 self
.msvc_arch_str
= "x86" if self
.arch
== "32" else "x64"
366 if toolchain_type
== "msvc":
367 # Make sure we're using the appropriate toolchain for the desired
369 compiler_parent_dir
= os
.path
.dirname(self
.compiler
)
370 selected_target_version
= os
.path
.basename(compiler_parent_dir
)
371 if selected_target_version
!= self
.msvc_arch_str
:
372 host_dir
= os
.path
.dirname(compiler_parent_dir
)
373 self
.compiler
= os
.path
.join(host_dir
, self
.msvc_arch_str
, "cl.exe")
376 'Using alternate compiler "{0}" to match selected target.'.format(
381 if self
.mode
== "link" or self
.mode
== "compile-and-link":
383 self
._find
_linker
("link")
384 if toolchain_type
== "msvc"
385 else self
._find
_linker
("lld-link", args
.tools_dir
)
388 raise ValueError("Unable to find an appropriate linker.")
390 self
.compile_env
, self
.link_env
= self
._get
_visual
_studio
_environment
()
392 def _find_linker(self
, name
, search_paths
=[]):
393 compiler_dir
= os
.path
.dirname(self
.compiler
)
394 linker_path
= find_executable(name
, [compiler_dir
] + search_paths
)
395 if linker_path
is None:
396 raise ValueError("Could not find '{}'".format(name
))
399 def _get_vc_install_dir(self
):
400 dir = os
.getenv("VCINSTALLDIR", None)
403 print("Using %VCINSTALLDIR% {}".format(dir))
406 dir = os
.getenv("VSINSTALLDIR", None)
409 print("Using %VSINSTALLDIR% {}".format(dir))
410 return os
.path
.join(dir, "VC")
412 dir = os
.getenv("VS2019INSTALLDIR", None)
415 print("Using %VS2019INSTALLDIR% {}".format(dir))
416 return os
.path
.join(dir, "VC")
418 dir = os
.getenv("VS2017INSTALLDIR", None)
421 print("Using %VS2017INSTALLDIR% {}".format(dir))
422 return os
.path
.join(dir, "VC")
424 dir = os
.getenv("VS2015INSTALLDIR", None)
427 print("Using %VS2015INSTALLDIR% {}".format(dir))
428 return os
.path
.join(dir, "VC")
431 def _get_vctools_version(self
):
432 ver
= os
.getenv("VCToolsVersion", None)
435 print("Using %VCToolsVersion% {}".format(ver
))
438 vcinstalldir
= self
._get
_vc
_install
_dir
()
439 vcinstalldir
= os
.path
.join(vcinstalldir
, "Tools", "MSVC")
440 subdirs
= next(os
.walk(vcinstalldir
))[1]
444 from packaging
import version
446 subdirs
.sort(key
=lambda x
: version
.parse(x
))
449 full_path
= os
.path
.join(vcinstalldir
, subdirs
[-1])
451 "Using VC tools version directory {0} found by directory walk.".format(
457 def _get_vctools_install_dir(self
):
458 dir = os
.getenv("VCToolsInstallDir", None)
461 print("Using %VCToolsInstallDir% {}".format(dir))
464 vcinstalldir
= self
._get
_vc
_install
_dir
()
467 vctoolsver
= self
._get
_vctools
_version
()
470 result
= os
.path
.join(vcinstalldir
, "Tools", "MSVC", vctoolsver
)
471 if not os
.path
.exists(result
):
475 "Using VC tools install dir {} found by directory walk".format(result
)
479 def _find_windows_sdk_in_registry_view(self
, view
):
482 installed_options_keys
= []
484 sam
= view | winreg
.KEY_READ
485 products_key
= winreg
.OpenKey(
486 winreg
.HKEY_LOCAL_MACHINE
,
487 r
"Software\Microsoft\Windows Kits\Installed Products",
492 # This is the GUID for the desktop component. If this is present
493 # then the components required for the Desktop SDK are installed.
494 # If not it will throw an exception.
495 winreg
.QueryValueEx(products_key
, "{5A3D81EC-D870-9ECF-D997-24BDA6644752}")
497 roots_key
= winreg
.OpenKey(
498 winreg
.HKEY_LOCAL_MACHINE
,
499 r
"Software\Microsoft\Windows Kits\Installed Roots",
503 root_dir
= winreg
.QueryValueEx(roots_key
, "KitsRoot10")
504 root_dir
= to_string(root_dir
[0])
508 # Installed SDK versions are stored as sub-keys of the
509 # 'Installed Roots' key. Find all of their names, then sort
512 ver_key
= winreg
.EnumKey(roots_key
, index
)
513 sdk_versions
.append(ver_key
)
520 from packaging
import version
522 sdk_versions
.sort(key
=lambda x
: version
.parse(x
), reverse
=True)
523 option_value_name
= "OptionId.DesktopCPP" + self
.msvc_arch_str
524 for v
in sdk_versions
:
526 version_subkey
= v
+ r
"\Installed Options"
527 key
= winreg
.OpenKey(roots_key
, version_subkey
)
528 installed_options_keys
.append(key
)
529 (value
, value_type
) = winreg
.QueryValueEx(key
, option_value_name
)
531 # The proper architecture is installed. Return the
535 "Found Installed Windows SDK v{0} at {1}".format(
547 for k
in installed_options_keys
:
551 def _find_windows_sdk_in_registry(self
):
552 # This could be a clang-cl cross-compile. If so, there's no registry
554 if sys
.platform
!= "win32":
557 print("Looking for Windows SDK in 64-bit registry.")
558 dir, ver
= self
._find
_windows
_sdk
_in
_registry
_view
(winreg
.KEY_WOW64_64KEY
)
559 if not dir or not ver
:
561 print("Looking for Windows SDK in 32-bit registry.")
562 dir, ver
= self
._find
_windows
_sdk
_in
_registry
_view
(winreg
.KEY_WOW64_32KEY
)
566 def _get_winsdk_dir(self
):
567 # If a Windows SDK is specified in the environment, use that. Otherwise
568 # try to find one in the Windows registry.
569 dir = os
.getenv("WindowsSdkDir", None)
570 if not dir or not os
.path
.exists(dir):
571 return self
._find
_windows
_sdk
_in
_registry
()
572 ver
= os
.getenv("WindowsSDKLibVersion", None)
574 return self
._find
_windows
_sdk
_in
_registry
()
576 ver
= ver
.rstrip("\\")
578 print("Using %WindowsSdkDir% {}".format(dir))
579 print("Using %WindowsSDKLibVersion% {}".format(ver
))
582 def _get_msvc_native_toolchain_dir(self
):
583 assert self
.toolchain_type
== "msvc"
584 compiler_dir
= os
.path
.dirname(self
.compiler
)
585 target_dir
= os
.path
.dirname(compiler_dir
)
586 host_name
= os
.path
.basename(target_dir
)
587 host_name
= host_name
[4:].lower()
588 return os
.path
.join(target_dir
, host_name
)
590 def _get_visual_studio_environment(self
):
591 vctools
= self
._get
_vctools
_install
_dir
()
592 winsdk
, winsdkver
= self
._get
_winsdk
_dir
()
594 if not vctools
and self
.verbose
:
595 print("Unable to find VC tools installation directory.")
596 if (not winsdk
or not winsdkver
) and self
.verbose
:
597 print("Unable to find Windows SDK directory.")
603 if vctools
is not None:
604 includes
= [["ATLMFC", "include"], ["include"]]
605 libs
= [["ATLMFC", "lib"], ["lib"]]
606 vcincludes
= [os
.path
.join(vctools
, *y
) for y
in includes
]
607 vclibs
= [os
.path
.join(vctools
, *y
) for y
in libs
]
608 if winsdk
is not None:
610 ["include", winsdkver
, "ucrt"],
611 ["include", winsdkver
, "shared"],
612 ["include", winsdkver
, "um"],
613 ["include", winsdkver
, "winrt"],
614 ["include", winsdkver
, "cppwinrt"],
616 libs
= [["lib", winsdkver
, "ucrt"], ["lib", winsdkver
, "um"]]
617 sdkincludes
= [os
.path
.join(winsdk
, *y
) for y
in includes
]
618 sdklibs
= [os
.path
.join(winsdk
, *y
) for y
in libs
]
620 includes
= vcincludes
+ sdkincludes
621 libs
= vclibs
+ sdklibs
622 libs
= [os
.path
.join(x
, self
.msvc_arch_str
) for x
in libs
]
626 if sys
.platform
== "win32":
628 x
: os
.environ
[x
] for x
in ["SystemDrive", "SystemRoot", "TMP", "TEMP"]
630 # The directory to mspdbcore.dll needs to be in PATH, but this is
631 # always in the native toolchain path, not the cross-toolchain
632 # path. So, for example, if we're using HostX64\x86 then we need
633 # to add HostX64\x64 to the path, and if we're using HostX86\x64
634 # then we need to add HostX86\x86 to the path.
635 if self
.toolchain_type
== "msvc":
636 defaultenv
["PATH"] = self
._get
_msvc
_native
_toolchain
_dir
()
640 compileenv
["INCLUDE"] = os
.pathsep
.join(includes
)
641 compileenv
.update(defaultenv
)
644 linkenv
["LIB"] = os
.pathsep
.join(libs
)
645 linkenv
.update(defaultenv
)
646 return (compileenv
, linkenv
)
648 def _ilk_file_names(self
):
649 if self
.mode
== "link":
652 return [self
._output
_name
(x
, ".ilk") for x
in self
.inputs
]
654 def _pdb_file_name(self
):
655 if self
.mode
== "compile":
657 return os
.path
.splitext(self
.output
)[0] + ".pdb"
659 def _get_compilation_command(self
, source
, obj
):
662 args
.append(self
.compiler
)
663 if self
.toolchain_type
== "clang-cl":
664 args
.append("-m" + self
.arch
)
666 if self
.opt
== "none":
668 elif self
.opt
== "basic":
670 elif self
.opt
== "lto":
671 if self
.toolchain_type
== "msvc":
675 args
.append("-flto=thin")
676 if self
.nodefaultlib
:
680 if self
.toolchain_type
== "clang-cl":
681 args
.append("-Xclang")
682 args
.append("-fkeep-static-consts")
683 args
.append("-fms-compatibility-version=19")
686 args
.append("/Fo" + obj
)
687 if self
.toolchain_type
== "clang-cl":
692 args
.append("/std:" + self
.std
)
694 return ("compiling", [source
], obj
, self
.compile_env
, args
)
696 def _get_link_command(self
):
698 args
.append(self
.linker
)
699 args
.append("/DEBUG:FULL")
700 args
.append("/INCREMENTAL:NO")
701 if self
.nodefaultlib
:
702 args
.append("/nodefaultlib")
703 args
.append("/entry:main")
704 args
.append("/PDB:" + self
._pdb
_file
_name
())
705 args
.append("/OUT:" + self
._exe
_file
_name
())
706 args
.extend(self
._obj
_file
_names
())
710 self
._obj
_file
_names
(),
711 self
._exe
_file
_name
(),
716 def build_commands(self
):
718 if self
.mode
== "compile" or self
.mode
== "compile-and-link":
719 for input, output
in zip(self
.inputs
, self
._obj
_file
_names
()):
720 commands
.append(self
._get
_compilation
_command
(input, output
))
721 if self
.mode
== "link" or self
.mode
== "compile-and-link":
722 commands
.append(self
._get
_link
_command
())
725 def output_files(self
):
727 if self
.mode
== "compile" or self
.mode
== "compile-and-link":
728 outputs
.extend(self
._ilk
_file
_names
())
729 outputs
.extend(self
._obj
_file
_names
())
730 if self
.mode
== "link" or self
.mode
== "compile-and-link":
731 outputs
.append(self
._pdb
_file
_name
())
732 outputs
.append(self
._exe
_file
_name
())
734 return [x
for x
in outputs
if x
is not None]
737 class GccBuilder(Builder
):
738 def __init__(self
, toolchain_type
, args
):
739 Builder
.__init
__(self
, toolchain_type
, args
, ".o")
740 if sys
.platform
== "darwin":
741 cmd
= ["xcrun", "--sdk", args
.apple_sdk
, "--show-sdk-path"]
742 self
.apple_sdk
= subprocess
.check_output(cmd
).strip().decode("utf-8")
744 def _add_m_option_if_needed(self
, args
):
745 # clang allows -m(32|64) for any target, gcc does not.
746 uname
= platform
.uname().machine
.lower()
747 if self
.toolchain_type
!= "gcc" or (
748 not "arm" in uname
and not "aarch64" in uname
750 args
.append("-m" + self
.arch
)
754 def _get_compilation_command(self
, source
, obj
):
757 args
.append(self
.compiler
)
758 args
= self
._add
_m
_option
_if
_needed
(args
)
761 if self
.opt
== "none":
763 elif self
.opt
== "basic":
765 elif self
.opt
== "lto":
766 args
.append("-flto=thin")
767 if self
.nodefaultlib
:
768 args
.append("-nostdinc")
769 args
.append("-static")
772 if sys
.platform
== "darwin":
773 args
.extend(["-isysroot", self
.apple_sdk
])
774 elif self
.objc_gnustep_inc
:
775 if source
.endswith(".m") or source
.endswith(".mm"):
776 args
.extend(["-fobjc-runtime=gnustep-2.0", "-I", self
.objc_gnustep_inc
])
777 if sys
.platform
== "win32":
779 ["-Xclang", "-gcodeview", "-Xclang", "--dependent-lib=msvcrtd"]
782 args
.extend(["--sysroot", self
.sysroot
])
785 args
.append("-std={0}".format(self
.std
))
787 args
.extend(["-o", obj
])
790 return ("compiling", [source
], obj
, None, args
)
792 def _get_link_command(self
):
794 args
.append(self
.compiler
)
795 args
= self
._add
_m
_option
_if
_needed
(args
)
797 if self
.nodefaultlib
:
798 args
.append("-nostdlib")
799 args
.append("-static")
801 if sys
.platform
== "darwin":
802 main_symbol
= "_main"
803 args
.append("-Wl,-e," + main_symbol
)
804 if sys
.platform
.startswith("netbsd"):
805 for x
in self
.lib_paths
:
806 args
+= ["-L" + x
, "-Wl,-rpath," + x
]
807 args
.extend(["-o", self
._exe
_file
_name
()])
808 args
.extend(self
._obj
_file
_names
())
810 if sys
.platform
== "darwin":
811 args
.extend(["-isysroot", self
.apple_sdk
])
812 elif self
.objc_gnustep_lib
:
813 args
.extend(["-L", self
.objc_gnustep_lib
, "-lobjc"])
814 if sys
.platform
== "linux":
815 args
.extend(["-Wl,-rpath," + self
.objc_gnustep_lib
])
816 elif sys
.platform
== "win32":
818 ["-fuse-ld=lld-link", "-g", "-Xclang", "--dependent-lib=msvcrtd"]
821 args
.extend(["--sysroot", self
.sysroot
])
823 return ("linking", self
._obj
_file
_names
(), self
._exe
_file
_name
(), None, args
)
825 def output_files(self
):
827 if self
.mode
== "compile" or self
.mode
== "compile-and-link":
828 outputs
.extend(self
._obj
_file
_names
())
829 if self
.mode
== "link" or self
.mode
== "compile-and-link":
830 outputs
.append(self
._exe
_file
_name
())
835 def indent(text
, spaces
):
836 def prefixed_lines():
837 prefix
= " " * spaces
838 for line
in text
.splitlines(True):
841 return "".join(prefixed_lines())
846 for status
, inputs
, output
, env
, child_args
in commands
:
848 inputs
= [os
.path
.basename(x
) for x
in inputs
]
849 output
= os
.path
.basename(output
)
850 print(status
+ " {0} -> {1}".format("+".join(inputs
), output
))
853 print(" Command Line: " + " ".join(child_args
))
855 print_environment(env
)
859 popen
= subprocess
.Popen(
861 stdout
=subprocess
.PIPE
,
862 stderr
=subprocess
.PIPE
,
864 universal_newlines
=True,
866 stdout
, stderr
= popen
.communicate()
868 if res
== -signal
.SIGINT
:
869 raise KeyboardInterrupt
871 print(indent(stdout
, 4))
874 print(indent(stderr
, 4))
883 file = o
if args
.verbose
else os
.path
.basename(o
)
884 print("Cleaning {0}".format(file))
886 if os
.path
.exists(o
):
890 print(" The file was successfully cleaned.")
892 print(" The file does not exist.")
895 print(" The file could not be removed.")
898 def fix_arguments(args
):
900 raise ValueError("No input files specified")
902 if args
.output
and args
.mode
== "compile" and len(args
.inputs
) > 1:
904 "Cannot specify -o with mode=compile and multiple source files. Use --outdir instead."
908 args
.inputs
= [os
.path
.abspath(x
) for x
in args
.inputs
]
910 # If user didn't specify the outdir, use the directory of the first input.
913 args
.outdir
= os
.path
.dirname(args
.output
)
915 args
.outdir
= os
.path
.dirname(args
.inputs
[0])
916 args
.outdir
= os
.path
.abspath(args
.outdir
)
917 args
.outdir
= os
.path
.normpath(args
.outdir
)
919 # If user specified a non-absolute path for the output file, append the
920 # output directory to it.
922 if not os
.path
.isabs(args
.output
):
923 args
.output
= os
.path
.join(args
.outdir
, args
.output
)
924 args
.output
= os
.path
.normpath(args
.output
)
929 (toolchain_type
, toolchain_path
) = find_toolchain(args
.compiler
, args
.tools_dir
)
930 if not toolchain_path
or not toolchain_type
:
931 print("Unable to find toolchain {0}".format(args
.compiler
))
935 print("Script Arguments:")
936 print(" Arch: " + args
.arch
)
937 print(" Compiler: " + args
.compiler
)
938 print(" Outdir: " + args
.outdir
)
939 print(" Output: " + args
.output
)
940 print(" Nodefaultlib: " + str(args
.nodefaultlib
))
941 print(" Opt: " + args
.opt
)
942 print(" Mode: " + args
.mode
)
943 print(" Clean: " + str(args
.clean
))
944 print(" Verbose: " + str(args
.verbose
))
945 print(" Dryrun: " + str(args
.dry
))
946 print(" Inputs: " + format_text(args
.inputs
, 0, 10))
947 print(" C/C++ Standard: " + str(args
.std
))
948 print("Script Environment:")
949 print_environment(os
.environ
)
951 args
.compiler
= toolchain_path
952 if not os
.path
.exists(args
.compiler
) and not args
.dry
:
953 raise ValueError("The toolchain {} does not exist.".format(args
.compiler
))
955 if toolchain_type
== "msvc" or toolchain_type
== "clang-cl":
956 builder
= MsvcBuilder(toolchain_type
, args
)
958 builder
= GccBuilder(toolchain_type
, args
)
961 clean(builder
.output_files())
963 cmds
= builder
.build_commands()