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 distutils
.version
import StrictVersion
446 subdirs
.sort(key
=lambda x
: StrictVersion(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 # Windows SDK version numbers consist of 4 dotted components, so we
521 # have to use LooseVersion, as StrictVersion supports 3 or fewer.
522 from distutils
.version
import LooseVersion
524 sdk_versions
.sort(key
=lambda x
: LooseVersion(x
), reverse
=True)
525 option_value_name
= "OptionId.DesktopCPP" + self
.msvc_arch_str
526 for v
in sdk_versions
:
528 version_subkey
= v
+ r
"\Installed Options"
529 key
= winreg
.OpenKey(roots_key
, version_subkey
)
530 installed_options_keys
.append(key
)
531 (value
, value_type
) = winreg
.QueryValueEx(key
, option_value_name
)
533 # The proper architecture is installed. Return the
537 "Found Installed Windows SDK v{0} at {1}".format(
549 for k
in installed_options_keys
:
553 def _find_windows_sdk_in_registry(self
):
554 # This could be a clang-cl cross-compile. If so, there's no registry
556 if sys
.platform
!= "win32":
559 print("Looking for Windows SDK in 64-bit registry.")
560 dir, ver
= self
._find
_windows
_sdk
_in
_registry
_view
(winreg
.KEY_WOW64_64KEY
)
561 if not dir or not ver
:
563 print("Looking for Windows SDK in 32-bit registry.")
564 dir, ver
= self
._find
_windows
_sdk
_in
_registry
_view
(winreg
.KEY_WOW64_32KEY
)
568 def _get_winsdk_dir(self
):
569 # If a Windows SDK is specified in the environment, use that. Otherwise
570 # try to find one in the Windows registry.
571 dir = os
.getenv("WindowsSdkDir", None)
572 if not dir or not os
.path
.exists(dir):
573 return self
._find
_windows
_sdk
_in
_registry
()
574 ver
= os
.getenv("WindowsSDKLibVersion", None)
576 return self
._find
_windows
_sdk
_in
_registry
()
578 ver
= ver
.rstrip("\\")
580 print("Using %WindowsSdkDir% {}".format(dir))
581 print("Using %WindowsSDKLibVersion% {}".format(ver
))
584 def _get_msvc_native_toolchain_dir(self
):
585 assert self
.toolchain_type
== "msvc"
586 compiler_dir
= os
.path
.dirname(self
.compiler
)
587 target_dir
= os
.path
.dirname(compiler_dir
)
588 host_name
= os
.path
.basename(target_dir
)
589 host_name
= host_name
[4:].lower()
590 return os
.path
.join(target_dir
, host_name
)
592 def _get_visual_studio_environment(self
):
593 vctools
= self
._get
_vctools
_install
_dir
()
594 winsdk
, winsdkver
= self
._get
_winsdk
_dir
()
596 if not vctools
and self
.verbose
:
597 print("Unable to find VC tools installation directory.")
598 if (not winsdk
or not winsdkver
) and self
.verbose
:
599 print("Unable to find Windows SDK directory.")
605 if vctools
is not None:
606 includes
= [["ATLMFC", "include"], ["include"]]
607 libs
= [["ATLMFC", "lib"], ["lib"]]
608 vcincludes
= [os
.path
.join(vctools
, *y
) for y
in includes
]
609 vclibs
= [os
.path
.join(vctools
, *y
) for y
in libs
]
610 if winsdk
is not None:
612 ["include", winsdkver
, "ucrt"],
613 ["include", winsdkver
, "shared"],
614 ["include", winsdkver
, "um"],
615 ["include", winsdkver
, "winrt"],
616 ["include", winsdkver
, "cppwinrt"],
618 libs
= [["lib", winsdkver
, "ucrt"], ["lib", winsdkver
, "um"]]
619 sdkincludes
= [os
.path
.join(winsdk
, *y
) for y
in includes
]
620 sdklibs
= [os
.path
.join(winsdk
, *y
) for y
in libs
]
622 includes
= vcincludes
+ sdkincludes
623 libs
= vclibs
+ sdklibs
624 libs
= [os
.path
.join(x
, self
.msvc_arch_str
) for x
in libs
]
628 if sys
.platform
== "win32":
630 x
: os
.environ
[x
] for x
in ["SystemDrive", "SystemRoot", "TMP", "TEMP"]
632 # The directory to mspdbcore.dll needs to be in PATH, but this is
633 # always in the native toolchain path, not the cross-toolchain
634 # path. So, for example, if we're using HostX64\x86 then we need
635 # to add HostX64\x64 to the path, and if we're using HostX86\x64
636 # then we need to add HostX86\x86 to the path.
637 if self
.toolchain_type
== "msvc":
638 defaultenv
["PATH"] = self
._get
_msvc
_native
_toolchain
_dir
()
642 compileenv
["INCLUDE"] = os
.pathsep
.join(includes
)
643 compileenv
.update(defaultenv
)
646 linkenv
["LIB"] = os
.pathsep
.join(libs
)
647 linkenv
.update(defaultenv
)
648 return (compileenv
, linkenv
)
650 def _ilk_file_names(self
):
651 if self
.mode
== "link":
654 return [self
._output
_name
(x
, ".ilk") for x
in self
.inputs
]
656 def _pdb_file_name(self
):
657 if self
.mode
== "compile":
659 return os
.path
.splitext(self
.output
)[0] + ".pdb"
661 def _get_compilation_command(self
, source
, obj
):
664 args
.append(self
.compiler
)
665 if self
.toolchain_type
== "clang-cl":
666 args
.append("-m" + self
.arch
)
668 if self
.opt
== "none":
670 elif self
.opt
== "basic":
672 elif self
.opt
== "lto":
673 if self
.toolchain_type
== "msvc":
677 args
.append("-flto=thin")
678 if self
.nodefaultlib
:
682 if self
.toolchain_type
== "clang-cl":
683 args
.append("-Xclang")
684 args
.append("-fkeep-static-consts")
685 args
.append("-fms-compatibility-version=19")
688 args
.append("/Fo" + obj
)
689 if self
.toolchain_type
== "clang-cl":
694 args
.append("/std:" + self
.std
)
696 return ("compiling", [source
], obj
, self
.compile_env
, args
)
698 def _get_link_command(self
):
700 args
.append(self
.linker
)
701 args
.append("/DEBUG:FULL")
702 args
.append("/INCREMENTAL:NO")
703 if self
.nodefaultlib
:
704 args
.append("/nodefaultlib")
705 args
.append("/entry:main")
706 args
.append("/PDB:" + self
._pdb
_file
_name
())
707 args
.append("/OUT:" + self
._exe
_file
_name
())
708 args
.extend(self
._obj
_file
_names
())
712 self
._obj
_file
_names
(),
713 self
._exe
_file
_name
(),
718 def build_commands(self
):
720 if self
.mode
== "compile" or self
.mode
== "compile-and-link":
721 for input, output
in zip(self
.inputs
, self
._obj
_file
_names
()):
722 commands
.append(self
._get
_compilation
_command
(input, output
))
723 if self
.mode
== "link" or self
.mode
== "compile-and-link":
724 commands
.append(self
._get
_link
_command
())
727 def output_files(self
):
729 if self
.mode
== "compile" or self
.mode
== "compile-and-link":
730 outputs
.extend(self
._ilk
_file
_names
())
731 outputs
.extend(self
._obj
_file
_names
())
732 if self
.mode
== "link" or self
.mode
== "compile-and-link":
733 outputs
.append(self
._pdb
_file
_name
())
734 outputs
.append(self
._exe
_file
_name
())
736 return [x
for x
in outputs
if x
is not None]
739 class GccBuilder(Builder
):
740 def __init__(self
, toolchain_type
, args
):
741 Builder
.__init
__(self
, toolchain_type
, args
, ".o")
742 if sys
.platform
== "darwin":
743 cmd
= ["xcrun", "--sdk", args
.apple_sdk
, "--show-sdk-path"]
744 self
.apple_sdk
= subprocess
.check_output(cmd
).strip().decode("utf-8")
746 def _get_compilation_command(self
, source
, obj
):
749 args
.append(self
.compiler
)
750 args
.append("-m" + self
.arch
)
753 if self
.opt
== "none":
755 elif self
.opt
== "basic":
757 elif self
.opt
== "lto":
758 args
.append("-flto=thin")
759 if self
.nodefaultlib
:
760 args
.append("-nostdinc")
761 args
.append("-static")
764 if sys
.platform
== "darwin":
765 args
.extend(["-isysroot", self
.apple_sdk
])
766 elif self
.objc_gnustep_inc
:
767 if source
.endswith(".m") or source
.endswith(".mm"):
768 args
.extend(["-fobjc-runtime=gnustep-2.0", "-I", self
.objc_gnustep_inc
])
769 if sys
.platform
== "win32":
771 ["-Xclang", "-gcodeview", "-Xclang", "--dependent-lib=msvcrtd"]
774 args
.extend(["--sysroot", self
.sysroot
])
777 args
.append("-std={0}".format(self
.std
))
779 args
.extend(["-o", obj
])
782 return ("compiling", [source
], obj
, None, args
)
784 def _get_link_command(self
):
786 args
.append(self
.compiler
)
787 args
.append("-m" + self
.arch
)
788 if self
.nodefaultlib
:
789 args
.append("-nostdlib")
790 args
.append("-static")
792 if sys
.platform
== "darwin":
793 main_symbol
= "_main"
794 args
.append("-Wl,-e," + main_symbol
)
795 if sys
.platform
.startswith("netbsd"):
796 for x
in self
.lib_paths
:
797 args
+= ["-L" + x
, "-Wl,-rpath," + x
]
798 args
.extend(["-o", self
._exe
_file
_name
()])
799 args
.extend(self
._obj
_file
_names
())
801 if sys
.platform
== "darwin":
802 args
.extend(["-isysroot", self
.apple_sdk
])
803 elif self
.objc_gnustep_lib
:
804 args
.extend(["-L", self
.objc_gnustep_lib
, "-lobjc"])
805 if sys
.platform
== "linux":
806 args
.extend(["-Wl,-rpath," + self
.objc_gnustep_lib
])
807 elif sys
.platform
== "win32":
809 ["-fuse-ld=lld-link", "-g", "-Xclang", "--dependent-lib=msvcrtd"]
812 args
.extend(["--sysroot", self
.sysroot
])
814 return ("linking", self
._obj
_file
_names
(), self
._exe
_file
_name
(), None, args
)
816 def output_files(self
):
818 if self
.mode
== "compile" or self
.mode
== "compile-and-link":
819 outputs
.extend(self
._obj
_file
_names
())
820 if self
.mode
== "link" or self
.mode
== "compile-and-link":
821 outputs
.append(self
._exe
_file
_name
())
826 def indent(text
, spaces
):
827 def prefixed_lines():
828 prefix
= " " * spaces
829 for line
in text
.splitlines(True):
832 return "".join(prefixed_lines())
837 for status
, inputs
, output
, env
, child_args
in commands
:
839 inputs
= [os
.path
.basename(x
) for x
in inputs
]
840 output
= os
.path
.basename(output
)
841 print(status
+ " {0} -> {1}".format("+".join(inputs
), output
))
844 print(" Command Line: " + " ".join(child_args
))
846 print_environment(env
)
850 popen
= subprocess
.Popen(
852 stdout
=subprocess
.PIPE
,
853 stderr
=subprocess
.PIPE
,
855 universal_newlines
=True,
857 stdout
, stderr
= popen
.communicate()
859 if res
== -signal
.SIGINT
:
860 raise KeyboardInterrupt
862 print(indent(stdout
, 4))
865 print(indent(stderr
, 4))
874 file = o
if args
.verbose
else os
.path
.basename(o
)
875 print("Cleaning {0}".format(file))
877 if os
.path
.exists(o
):
881 print(" The file was successfully cleaned.")
883 print(" The file does not exist.")
886 print(" The file could not be removed.")
889 def fix_arguments(args
):
891 raise ValueError("No input files specified")
893 if args
.output
and args
.mode
== "compile" and len(args
.inputs
) > 1:
895 "Cannot specify -o with mode=compile and multiple source files. Use --outdir instead."
899 args
.inputs
= [os
.path
.abspath(x
) for x
in args
.inputs
]
901 # If user didn't specify the outdir, use the directory of the first input.
904 args
.outdir
= os
.path
.dirname(args
.output
)
906 args
.outdir
= os
.path
.dirname(args
.inputs
[0])
907 args
.outdir
= os
.path
.abspath(args
.outdir
)
908 args
.outdir
= os
.path
.normpath(args
.outdir
)
910 # If user specified a non-absolute path for the output file, append the
911 # output directory to it.
913 if not os
.path
.isabs(args
.output
):
914 args
.output
= os
.path
.join(args
.outdir
, args
.output
)
915 args
.output
= os
.path
.normpath(args
.output
)
920 (toolchain_type
, toolchain_path
) = find_toolchain(args
.compiler
, args
.tools_dir
)
921 if not toolchain_path
or not toolchain_type
:
922 print("Unable to find toolchain {0}".format(args
.compiler
))
926 print("Script Arguments:")
927 print(" Arch: " + args
.arch
)
928 print(" Compiler: " + args
.compiler
)
929 print(" Outdir: " + args
.outdir
)
930 print(" Output: " + args
.output
)
931 print(" Nodefaultlib: " + str(args
.nodefaultlib
))
932 print(" Opt: " + args
.opt
)
933 print(" Mode: " + args
.mode
)
934 print(" Clean: " + str(args
.clean
))
935 print(" Verbose: " + str(args
.verbose
))
936 print(" Dryrun: " + str(args
.dry
))
937 print(" Inputs: " + format_text(args
.inputs
, 0, 10))
938 print(" C/C++ Standard: " + str(args
.std
))
939 print("Script Environment:")
940 print_environment(os
.environ
)
942 args
.compiler
= toolchain_path
943 if not os
.path
.exists(args
.compiler
) and not args
.dry
:
944 raise ValueError("The toolchain {} does not exist.".format(args
.compiler
))
946 if toolchain_type
== "msvc" or toolchain_type
== "clang-cl":
947 builder
= MsvcBuilder(toolchain_type
, args
)
949 builder
= GccBuilder(toolchain_type
, args
)
952 clean(builder
.output_files())
954 cmds
= builder
.build_commands()