diff --git a/share/cpp2b.build.cppm.tpl b/share/cpp2b.build.cppm.tpl index 8c6d687..587e09c 100644 --- a/share/cpp2b.build.cppm.tpl +++ b/share/cpp2b.build.cppm.tpl @@ -3,7 +3,7 @@ module; #if defined(_WIN32) # define CPP2B_BUILD_API extern "C" __declspec(dllexport) #else -# define CPP2B_BUILD_API __attribute__((visibility("default"))) +# define CPP2B_BUILD_API extern "C" __attribute__((visibility("default"))) #endif export module cpp2b.build; diff --git a/share/cpp2b.cppm.tpl b/share/cpp2b.cppm.tpl index 04de6d6..3a7071d 100644 --- a/share/cpp2b.cppm.tpl +++ b/share/cpp2b.cppm.tpl @@ -1,6 +1,15 @@ +module; + +#ifdef _MSC_VER +# include +#else +# include +#endif + export module cpp2b; import std; +import std.compat; export namespace cpp2b { @@ -48,3 +57,22 @@ constexpr auto install_dir() -> const std::string_view { } } // namespace cpp2b + +export namespace cpp2b::env { +inline auto set_var(const std::string& name, const std::string& value) -> void { +#if defined(_MSC_VER) + SetEnvironmentVariableA(name.c_str(), value.c_str()); +#else + setenv(name.c_str(), value.c_str(), 1); +#endif +} + +inline auto get_var(const std::string& name) -> std::optional { + auto val = std::getenv(name.c_str()); + if(val != nullptr) { + return std::string{val}; + } + + return {}; +} +} diff --git a/src/main.cpp2 b/src/main.cpp2 index 4aa184e..464de7e 100644 --- a/src/main.cpp2 +++ b/src/main.cpp2 @@ -306,6 +306,15 @@ run_with_msvc_env_vars: (args) -> int = { return std::system(cmd_str.c_str()); } +run_with_args: (args) -> int = { + cmd_str: std::string = ""; + for args do (arg) { + cmd_str += " (arg)$"; + } + + return std::system(cmd_str.c_str()); +} + main: (args) -> int = { using std::views::drop; @@ -324,6 +333,14 @@ main: (args) -> int = { } else { log_info("using vs tools {}", getenv_sv("VCToolsVersion").expect("msvc env internal error")); } + } else { + libcxx_lib_dir := get_libcxx_build_root() / "lib"; + ld_library_path := cpp2b::env::get_var("LD_LIBRARY_PATH"); + if !ld_library_path || !ld_library_path*.contains(libcxx_lib_dir.string()) { + log_info("setting LD_LIBRARY_PATH to '{}'", libcxx_lib_dir.string()); + cpp2b::env::set_var("LD_LIBRARY_PATH", libcxx_lib_dir.string()); + return run_with_args(argz); + } } ensure_dir(".cache/cpp2/mod"); @@ -497,7 +514,47 @@ build_binary_result: @struct type = { log_path: fs::path = (); duration: std::chrono::milliseconds = (); } + +cl_build_binary_cmd: (info: cpp2b_source_binary_info, bin_outpath: fs::path) -> std::string = { + cppfront_include_dir := fs::absolute(".cache/cpp2/repos/hsutter/cppfront/include"); + transpiled_src := fs::absolute(".cache/cpp2/source") / fs::path(info.src).replace_extension(".cpp"); + d := fs::absolute(modules_dir()); + cmd_str: std::string = "cl /nologo /std:c++latest /W4 /MDd /EHsc /DEBUG:full /Zi /FC"; + for info.imports do (imp: std::string) { + imp_bmi := d / ("(imp)$.ifc"); + imp_obj := d / ("(imp)$.obj"); + cmd_str += " /reference \"(imp_bmi.string())$\" \"(imp_obj.string())$\""; + } + cmd_str += " \"(transpiled_src.string())$\""; + cmd_str += " -I\"(cppfront_include_dir.string())$\""; + cmd_str += " /Fe\"(bin_outpath.string())$\""; + return cmd_str; +} + +unix_build_binary_cmd: (compiler_cmd: std::string, info: cpp2b_source_binary_info, bin_outpath: fs::path) -> std::string = { + libcxx_inc_dir := get_libcxx_build_root() / "include" / "c++" / "v1"; + libcxx_lib_dir := get_libcxx_build_root() / "lib"; + cppfront_include_dir := fs::absolute(".cache/cpp2/repos/hsutter/cppfront/include"); + transpiled_src := fs::absolute(".cache/cpp2/source") / fs::path(info.src).replace_extension(".cpp"); + d := fs::absolute(modules_dir()); + cmd_str: std::string = std::format("{} -stdlib=libc++ -fPIC", compiler_cmd); + for info.imports do (imp: std::string) { + cmd_str += " \"" + (d / ("(imp)$.pcm")).string() + "\""; + } + cmd_str += " \"(transpiled_src.string())$\""; + cmd_str += " -std=c++23 -fexperimental-library"; + cmd_str += std::format(" -fprebuilt-module-path={}", d.string()); + cmd_str += std::format(" -L{}", libcxx_lib_dir.string()); + cmd_str += std::format(" -isystem {}", libcxx_inc_dir.string()); + cmd_str += " -lc++abi -lc++ -lm -static -fuse-ld=lld"; + cmd_str += " -I\"(cppfront_include_dir.string())$\""; + cmd_str += " -o \"(bin_outpath.string())$\""; + return cmd_str; +} + + build_binary: (info: cpp2b_source_binary_info) -> build_binary_result = { + compiler :== cpp2b::compiler(); bin_basename: fs::path; if info.preferred_name { bin_basename = fs::path(info.preferred_name*); @@ -512,28 +569,19 @@ build_binary: (info: cpp2b_source_binary_info) -> build_binary_result = { bin_basename.replace_extension(executable_extension()); } - cppfront_include_dir := fs::absolute(".cache/cpp2/repos/hsutter/cppfront/include"); bin_outpath := fs::absolute(".cache/cpp2/bin") / bin_basename; - transpiled_src := fs::absolute(".cache/cpp2/source") / fs::path(info.src).replace_extension(".cpp"); log_path := fs::absolute(".cache/cpp2/log/compile") / fs::path(info.src).replace_extension(".log"); ensure_dir(log_path.parent_path()); ensure_dir(bin_outpath.parent_path()); - if cpp2b::compiler() != cpp2b::compiler_type::msvc { - log_error("TODO: build_binary non-msvc support"); - std::abort(); - } - d := fs::absolute(modules_dir()); - cmd_str: std::string = "cl /nologo /std:c++latest /W4 /MDd /EHsc /DEBUG:full /Zi /FC"; - for info.imports do (imp: std::string) { - imp_bmi := d / ("(imp)$.ifc"); - imp_obj := d / ("(imp)$.obj"); - cmd_str += " /reference \"(imp_bmi.string())$\" \"(imp_obj.string())$\""; - } - cmd_str += " \"(transpiled_src .string())$\""; - cmd_str += " -I\"(cppfront_include_dir.string())$\""; - cmd_str += " /Fe\"(bin_outpath.string())$\""; + + cmd_str: std::string = ""; + if compiler == cpp2b::compiler_type::msvc { cmd_str = cl_build_binary_cmd(info, bin_outpath); } + else if compiler == cpp2b::compiler_type::clang { cmd_str = unix_build_binary_cmd("clang", info, bin_outpath); } + else if compiler == cpp2b::compiler_type::gcc { cmd_str = unix_build_binary_cmd("gcc", info, bin_outpath); } + else { log_error("Unsupported compiler"); std::abort(); } + cmd_str += " (cmd_log_output(fs::absolute(log_path)))$"; result: build_binary_result = (); @@ -568,19 +616,9 @@ cpp2b_detail_build: (copy _impl: *cpp2b_detail_build_impl) -> void = { // empty. this is just so we can decltype the signature } -build_build_script: (info: cpp2b_source_build_info) -> build_binary_result = { +cl_build_build_script_cmd: (info: cpp2b_source_build_info, bin_outpath: fs::path) -> std::string = { cppfront_include_dir := fs::absolute(".cache/cpp2/repos/hsutter/cppfront/include"); - bin_outpath := fs::absolute(".cache/cpp2/bin") / fs::path(info.src).replace_extension(shared_library_extension()); transpiled_src := fs::absolute(".cache/cpp2/source") / fs::path(info.src).replace_extension(".cpp"); - log_path := fs::absolute(".cache/cpp2/log/compile") / fs::path(info.src).replace_extension(".log"); - ensure_dir(log_path.parent_path()); - ensure_dir(bin_outpath.parent_path()); - - if cpp2b::compiler() != cpp2b::compiler_type::msvc { - log_error("TODO: build_build_script non-msvc support"); - std::abort(); - } - d := fs::absolute(modules_dir()); cmd_str: std::string = "cl /nologo /std:c++latest /W4 /MDd /EHsc /LDd /DLL"; for info.imports do (imp: std::string) { @@ -592,6 +630,46 @@ build_build_script: (info: cpp2b_source_build_info) -> build_binary_result = { cmd_str += " -I\"(cppfront_include_dir.string())$\""; cmd_str += " /Fe\"(fs::relative(bin_outpath).string())$\""; cmd_str += " /link"; + return cmd_str; +} + + +unix_build_build_script_cmd: (compiler_cmd: std::string, info: cpp2b_source_build_info, bin_outpath: fs::path) -> std::string = { + libcxx_inc_dir := get_libcxx_build_root() / "include" / "c++" / "v1"; + libcxx_lib_dir := get_libcxx_build_root() / "lib"; + cppfront_include_dir := fs::absolute(".cache/cpp2/repos/hsutter/cppfront/include"); + transpiled_src := fs::absolute(".cache/cpp2/source") / fs::path(info.src).replace_extension(".cpp"); + d := fs::absolute(modules_dir()); + cmd_str: std::string = std::format("{} -stdlib=libc++ -shared", compiler_cmd); + for info.imports do (imp: std::string) { + cmd_str += " \"" + (d / ("(imp)$.pcm")).string() + "\""; + } + cmd_str += " \"(transpiled_src.string())$\""; + cmd_str += " -std=c++23 -fexperimental-library -fPIC"; + cmd_str += std::format(" -fprebuilt-module-path={}", d.string()); + cmd_str += std::format(" -L{}", libcxx_lib_dir.string()); + cmd_str += std::format(" -isystem {}", libcxx_inc_dir.string()); + cmd_str += " -lc++abi -lc++ -lm -fuse-ld=lld"; + cmd_str += " -I\"(cppfront_include_dir.string())$\""; + cmd_str += " -o \"(bin_outpath.string())$\""; + return cmd_str; +} + + +build_build_script: (info: cpp2b_source_build_info) -> build_binary_result = { + compiler :== cpp2b::compiler(); + bin_outpath := fs::absolute(".cache/cpp2/bin") / fs::path(info.src).replace_extension(shared_library_extension()); + log_path := fs::absolute(".cache/cpp2/log/compile") / fs::path(info.src).replace_extension(".log"); + ensure_dir(log_path.parent_path()); + ensure_dir(bin_outpath.parent_path()); + + d := fs::absolute(modules_dir()); + cmd_str: std::string = ""; + if compiler == cpp2b::compiler_type::msvc { cmd_str = cl_build_build_script_cmd(info, bin_outpath); } + else if compiler == cpp2b::compiler_type::clang { cmd_str = unix_build_build_script_cmd("clang", info, bin_outpath); } + else if compiler == cpp2b::compiler_type::gcc { cmd_str = unix_build_build_script_cmd("gcc", info, bin_outpath); } + else { log_error("Unsupported compiler"); std::abort(); } + cmd_str += " (cmd_log_output(fs::relative(log_path)))$"; result: build_binary_result = ();