32f125624381e7d6db4555491d82043e6dde7624
[nmigen.git] / nmigen / _toolchain / cxx.py
1 import tempfile
2 import sysconfig
3 import os.path
4 from distutils import ccompiler
5
6
7 __all__ = ["build_cxx"]
8
9
10 def build_cxx(*, cxx_sources, output_name, include_dirs, macros):
11 build_dir = tempfile.TemporaryDirectory(prefix="nmigen_cxx_")
12
13 cwd = os.getcwd()
14 try:
15 # Unforuntately, `ccompiler.compile` assumes the paths are relative, and interprets
16 # the directory name of the source path specially. That makes it necessary to build in
17 # the output directory directly.
18 os.chdir(build_dir.name)
19
20 cc_driver = ccompiler.new_compiler()
21 cc_driver.output_dir = "."
22
23 cc = sysconfig.get_config_var("CC")
24 cxx = sysconfig.get_config_var("CXX")
25 cflags = sysconfig.get_config_var("CCSHARED")
26 ld_ldflags = sysconfig.get_config_var("LDCXXSHARED")
27 cc_driver.set_executables(
28 compiler=f"{cc} {cflags}",
29 compiler_so=f"{cc} {cflags}",
30 compiler_cxx=f"{cxx} {cflags}",
31 linker_so=ld_ldflags,
32 )
33
34 for include_dir in include_dirs:
35 cc_driver.add_include_dir(include_dir)
36 for macro in macros:
37 cc_driver.define_macro(macro)
38 for cxx_filename, cxx_source in cxx_sources.items():
39 with open(cxx_filename, "w") as f:
40 f.write(cxx_source)
41
42 cxx_filenames = list(cxx_sources.keys())
43 obj_filenames = cc_driver.object_filenames(cxx_filenames)
44 so_filename = cc_driver.shared_object_filename(output_name)
45
46 cc_driver.compile(cxx_filenames)
47 cc_driver.link_shared_object(obj_filenames, output_filename=so_filename, target_lang="c++")
48
49 return build_dir, so_filename
50
51 finally:
52 os.chdir(cwd)