summaryrefslogtreecommitdiff
path: root/src/configure.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/configure.cc')
-rw-r--r--src/configure.cc343
1 files changed, 259 insertions, 84 deletions
diff --git a/src/configure.cc b/src/configure.cc
index 995e340..f9513d1 100644
--- a/src/configure.cc
+++ b/src/configure.cc
@@ -8,8 +8,9 @@
#include <fstream>
#include <optional>
#include <span>
-
-#include <getoptpp/getoptpp.hpp>
+#include <cstring>
+#include <vector>
+#include <deque>
#include "execute.h"
#include "ctor.h"
@@ -18,6 +19,7 @@
#include "externals.h"
#include "tools.h"
#include "util.h"
+#include "argparser.h"
const std::filesystem::path configurationFile("configuration.cc");
const std::filesystem::path configHeaderFile("config.h");
@@ -25,17 +27,37 @@ const std::filesystem::path configHeaderFile("config.h");
std::map<std::string, std::string> external_includedir;
std::map<std::string, std::string> external_libdir;
+#if !defined(_WIN32)
const ctor::configuration& __attribute__((weak)) ctor::get_configuration()
+#else
+const ctor::configuration& default_get_configuration()
+#endif
{
static ctor::configuration cfg;
static bool initialised{false};
if(!initialised)
{
- cfg.build_toolchain = getToolChain(cfg.get(ctor::cfg::build_cxx, "/usr/bin/g++"));
+ std::string cxx_prog{"c++"};
+ auto cxx_env = std::getenv("CXX");
+ if(cxx_env)
+ {
+ cxx_prog = cxx_env;
+ }
+
+ cfg.build_toolchain = getToolChain(cfg.get(ctor::cfg::build_cxx, cxx_prog));
+
initialised = true;
}
return cfg;
}
+#if defined(_WIN32)
+// Hack to make ctor::get_configuration "weak" linked
+// See:
+// https://stackoverflow.com/questions/2290587/gcc-style-weak-linking-in-visual-studio
+// and
+// https://stackoverflow.com/questions/11849853/how-to-list-functions-present-in-object-file
+#pragma comment(linker, "/alternatename:?get_configuration@ctor@@YAABUconfiguration@1@XZ=?default_get_configuration@@YAABUconfiguration@ctor@@XZ")
+#endif
namespace ctor {
std::optional<std::string> includedir;
@@ -69,7 +91,8 @@ bool ctor::configuration::has(const std::string& key) const
return tools.find(key) != tools.end();
}
-const std::string& ctor::configuration::get(const std::string& key, const std::string& default_value) const
+std::string ctor::configuration::get(const std::string& key,
+ const std::string& default_value) const
{
if(key == ctor::cfg::ctor_includedir && ctor::includedir)
{
@@ -91,14 +114,67 @@ const std::string& ctor::configuration::get(const std::string& key, const std::s
return ctor::conf_values[key];
}
- if(has(key))
+ if(tools.find(key) != tools.end())
{
return tools.at(key);
}
+ if(key == ctor::cfg::build_cxx)
+ {
+ auto e = std::getenv("CXX");
+ if(e)
+ {
+ return e;
+ }
+ }
+
+ if(key == ctor::cfg::build_cc)
+ {
+ auto e = std::getenv("CC");
+ if(e)
+ {
+ return e;
+ }
+ }
+
+ if(key == ctor::cfg::build_ld)
+ {
+ auto e = std::getenv("LD");
+ if(e)
+ {
+ return e;
+ }
+ }
+
+ if(key == ctor::cfg::build_ar)
+ {
+ auto e = std::getenv("AR");
+ if(e)
+ {
+ return e;
+ }
+ }
+
return default_value;
}
+std::string ctor::configuration::getenv(const std::string& key) const
+{
+ auto envit = env.find(key);
+ if(envit != env.end())
+ {
+ return envit->second;
+ }
+
+ auto sysenv = std::getenv(key.data());
+ if(sysenv)
+ {
+ return sysenv;
+ }
+
+ return {};
+}
+
class Args
: public std::vector<char*>
{
@@ -136,6 +212,9 @@ std::ostream& operator<<(std::ostream& stream, const ctor::toolchain& toolchain)
case ctor::toolchain::gcc:
stream << "ctor::toolchain::gcc";
break;
+ case ctor::toolchain::msvc:
+ stream << "ctor::toolchain::msvc";
+ break;
case ctor::toolchain::clang:
stream << "ctor::toolchain::clang";
break;
@@ -210,8 +289,7 @@ int regenerateCache(ctor::settings& settings,
{
Args vargs(args);
- dg::Options opt;
- int key{128};
+ arg::Parser<std::string> opt(static_cast<int>(vargs.size()), vargs.data());
std::string build_arch_prefix;
std::string build_path;
@@ -225,91 +303,103 @@ int regenerateCache(ctor::settings& settings,
std::string ctor_libdir;
std::string builddir;
- opt.add("build-dir", required_argument, 'b',
- "Set output directory for build files (default: '" +
- settings.builddir + "').",
- [&]() {
- settings.builddir = optarg;
- builddir = optarg;
+ opt.add('b', "--build-dir",
+ std::function([&](std::string arg)
+ {
+ settings.builddir = arg;
+ builddir = arg;
return 0;
- });
+ }),
+ "Set output directory for build files (default: '" +
+ settings.builddir + "').");
- opt.add("verbose", no_argument, 'v',
- "Be verbose. Add multiple times for more verbosity.",
- [&]() {
+ opt.add('v', "--verbose",
+ std::function([&]()
+ {
settings.verbose++;
return 0;
- });
+ }),
+ "Be verbose. Add multiple times for more verbosity.");
- opt.add("cc", required_argument, key++,
- "Use specified c-compiler instead of gcc.",
- [&]() {
- cc_prog = optarg;
+ opt.add({}, "--cc",
+ std::function([&](std::string arg)
+ {
+ cc_prog = arg;
return 0;
- });
+ }),
+ "Use specified c-compiler instead of gcc.");
- opt.add("cxx", required_argument, key++,
- "Use specified c++-compiler instead of g++.",
- [&]() {
- cxx_prog = optarg;
+ opt.add({}, "--cxx",
+ std::function([&](std::string arg)
+ {
+ cxx_prog = arg;
return 0;
- });
+ }),
+ "Use specified c++-compiler instead of g++.");
- opt.add("ar", required_argument, key++,
- "Use specified archiver instead of ar.",
- [&]() {
- ar_prog = optarg;
+ opt.add({}, "--ar",
+ std::function([&](std::string arg)
+ {
+ ar_prog = arg;
return 0;
- });
+ }),
+ "Use specified archiver instead of ar.");
- opt.add("ld", required_argument, key++,
- "Use specified linker instead of ld.",
- [&]() {
- ld_prog = optarg;
+ opt.add({}, "--ld",
+ std::function([&](std::string arg)
+ {
+ ld_prog = arg;
return 0;
- });
+ }),
+ "Use specified linker instead of ld.");
- opt.add("build", required_argument, key++,
- "Configure for building on specified architecture.",
- [&]() {
- build_arch_prefix = optarg;
+ opt.add({}, "--build",
+ std::function([&](std::string arg)
+ {
+ build_arch_prefix = arg;
return 0;
- });
+ }),
+ "Configure for building on specified architecture.");
- opt.add("build-path", required_argument, key++,
- "Set path to build tool-chain.",
- [&]() {
- build_path = optarg;
+ opt.add({}, "--build-path",
+ std::function([&](std::string arg)
+ {
+ build_path = arg;
return 0;
- });
+ }),
+ "Set path to build tool-chain.");
- opt.add("host", required_argument, key++,
- "Cross-compile to build programs to run on specified architecture.",
- [&]() {
- host_arch_prefix = optarg;
+ opt.add({}, "--host",
+ std::function([&](std::string arg)
+ {
+ host_arch_prefix = arg;
return 0;
- });
+ }),
+ "Cross-compile to build programs to run on specified architecture.");
- opt.add("host-path", required_argument, key++,
- "Set path to cross-compile tool-chain.",
- [&]() {
- host_path = optarg;
+ opt.add({}, "--host-path",
+ std::function([&](std::string arg)
+ {
+ host_path = arg;
return 0;
- });
+ }),
+ "Set path to cross-compile tool-chain.");
- opt.add("ctor-includedir", required_argument, key++,
- "Set path to ctor header file, used for re-compiling.",
- [&]() {
- ctor_includedir = optarg;
+ opt.add({}, "--ctor-includedir",
+ std::function([&](std::string arg)
+ {
+ ctor_includedir = arg;
return 0;
- });
+ }),
+ "Set path to ctor header file, used for re-compiling.");
- opt.add("ctor-libdir", required_argument, key++,
- "Set path to ctor library file, used for re-compiling.",
- [&]() {
- ctor_libdir = optarg;
+ opt.add({}, "--ctor-libdir",
+ std::function([&](std::string arg)
+ {
+ ctor_libdir = arg;
return 0;
- });
+ }),
+ "Set path to ctor library file, used for re-compiling.");
// Resolv externals
ctor::external_configurations externalConfigs;
@@ -324,19 +414,21 @@ int regenerateCache(ctor::settings& settings,
auto add_path_args =
[&](const std::string& arg_name)
{
- opt.add(arg_name + "-includedir", required_argument, key++,
- "Set path to " + arg_name + " header file.",
- [&]() {
- external_includedir[arg_name] = optarg;
+ opt.add({}, "--" + arg_name + "-includedir",
+ std::function([&](std::string arg)
+ {
+ external_includedir[arg_name] = arg;
return 0;
- });
+ }),
+ "Set path to " + arg_name + " header file.");
- opt.add(arg_name + "-libdir", required_argument, key++,
- "Set path to " + arg_name + " libraries.",
- [&]() {
- external_libdir[arg_name] = optarg;
+ opt.add({}, "--" + arg_name + "-libdir",
+ std::function([&](std::string arg)
+ {
+ external_libdir[arg_name] = arg;
return 0;
- });
+ }),
+ "Set path to " + arg_name + " libraries.");
};
for(const auto& ext : externalConfigs)
@@ -356,18 +448,57 @@ int regenerateCache(ctor::settings& settings,
}
- opt.add("help", no_argument, 'h',
- "Print this help text.",
- [&]() {
+ opt.add('h', "--help",
+ std::function([&]() -> int
+ {
std::cout << "Configure how to build with " << name << "\n";
std::cout << "Usage: " << name << " configure [options]\n\n";
std::cout << "Options:\n";
opt.help();
exit(0);
- return 0;
- });
+ }),
+ "Print this help text.");
+
+ opt.set_err_cb(
+ [&](arg::error err, std::string_view arg)
+ {
+ switch(err)
+ {
+ case arg::error::invalid_arg:
+ std::cerr << opt.prog_name() <<
+ ": invalid argument for option '" << arg << "'\n";
+ std::cerr << "Type '" << opt.prog_name() <<
+ " -h' for more information.\n";
+ break;
- opt.process(static_cast<int>(vargs.size()), vargs.data());
+ case arg::error::missing_arg:
+ std::cerr << opt.prog_name() << ": option requires and argument '" <<
+ arg << "'\n";
+ std::cerr << "Type '" << opt.prog_name() <<
+ " -h' for more information.\n";
+ break;
+
+ case arg::error::invalid_opt:
+ std::cerr << opt.prog_name() << ": invalid option '" << arg << "'\n";
+ std::cerr << "Type '" << opt.prog_name() <<
+ " -h' for more information.\n";
+ break;
+ }
+ });
+
+ opt.set_pos_cb(
+ [&](std::string_view)
+ {
+ std::cerr <<
+ "The configure subcommand doesn't use positional arguments.\n";
+ return 1;
+ });
+
+ auto res = opt.parse();
+ if(res != 0)
+ {
+ return res;
+ }
if(host_arch_prefix.empty())
{
@@ -651,6 +782,7 @@ int regenerateCache(ctor::settings& settings,
{
ctor::conf_values[ctor::cfg::builddir] = builddir;
}
+
ctor::conf_values[ctor::cfg::host_cxx] = host_cxx;
ctor::conf_values[ctor::cfg::build_cxx] = build_cxx;
@@ -839,12 +971,24 @@ int configure(const ctor::settings& global_settings, int argc, char* argv[])
env["CC"] = cc_env;
}
+ auto cflags_env = getenv("CFLAGS");
+ if(cflags_env)
+ {
+ env["CFLAGS"] = cflags_env;
+ }
+
auto cxx_env = getenv("CXX");
if(cxx_env)
{
env["CXX"] = cxx_env;
}
+ auto cxxflags_env = getenv("CXXFLAGS");
+ if(cxxflags_env)
+ {
+ env["CXXFLAGS"] = cxxflags_env;
+ }
+
auto ar_env = getenv("AR");
if(ar_env)
{
@@ -857,12 +1001,43 @@ int configure(const ctor::settings& global_settings, int argc, char* argv[])
env["LD"] = ld_env;
}
+ auto ldflags_env = getenv("LDFLAGS");
+ if(ldflags_env)
+ {
+ env["LDFLAGS"] = ldflags_env;
+ }
+
auto path_env = getenv("PATH");
if(path_env)
{
env["PATH"] = path_env;
}
+ // Env vars for msvc
+ auto cl_env = getenv("CL");
+ if(cl_env)
+ {
+ env["CL"] = cl_env;
+ }
+
+ auto lib_env = getenv("LIB");
+ if(lib_env)
+ {
+ env["LIB"] = lib_env;
+ }
+
+ auto link_env = getenv("LINK");
+ if(link_env)
+ {
+ env["LINK"] = link_env;
+ }
+
+ auto include_env = getenv("INCLUDE");
+ if(include_env)
+ {
+ env["INCLUDE"] = include_env;
+ }
+
auto ret = regenerateCache(settings, args_span[0], args, env);
if(ret != 0)
{