summaryrefslogtreecommitdiff
path: root/libcppbuild.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libcppbuild.cc')
-rw-r--r--libcppbuild.cc163
1 files changed, 137 insertions, 26 deletions
diff --git a/libcppbuild.cc b/libcppbuild.cc
index 927fe72..1fa1bc3 100644
--- a/libcppbuild.cc
+++ b/libcppbuild.cc
@@ -25,6 +25,35 @@
#include <unistd.h>
+
+namespace
+{
+std::filesystem::path configurationFile("configuration.cc");
+const std::map<std::string, std::string> default_configuration{};
+}
+const std::map<std::string, std::string>& __attribute__((weak)) configuration()
+{
+ return default_configuration;
+}
+
+bool hasConfiguration(const std::string& key)
+{
+ const auto& c = configuration();
+ return c.find(key) != c.end();
+}
+
+const std::string& getConfiguration(const std::string& key,
+ const std::string& defaultValue)
+{
+ const auto& c = configuration();
+ if(hasConfiguration(key))
+ {
+ return c.at(key);
+ }
+
+ return defaultValue;
+}
+
using namespace std::chrono_literals;
std::list<std::shared_ptr<Task>> taskFactory(const BuildConfiguration& config,
@@ -151,6 +180,24 @@ void recompileCheck(const Settings& settings, int argc, char* argv[])
std::filesystem::path binFile("cppbuild");
+ if(std::filesystem::exists(configurationFile))
+ {
+ args.push_back(configurationFile.string());
+
+ if(std::filesystem::last_write_time(binFile) <=
+ std::filesystem::last_write_time(configurationFile))
+ {
+ dirty = true;
+ }
+
+ const auto& c = configuration();
+ if(&c == &default_configuration)
+ {
+ // configuration.cc exists, but currently compiled with the default one.
+ dirty = true;
+ }
+ }
+
if(settings.verbose > 1)
{
std::cout << "Recompile check (" << numConfigFiles << "):\n";
@@ -183,10 +230,11 @@ void recompileCheck(const Settings& settings, int argc, char* argv[])
if(dirty)
{
std::cout << "Rebuilding config\n";
- auto ret = execute("/usr/bin/g++", args);
+ auto tool = getConfiguration("host-cpp", "/usr/bin/g++");
+ auto ret = execute(tool, args, settings.verbose > 0);
if(ret != 0)
{
- std::cerr << "Failed.\n";
+ std::cerr << "Failed: ." << ret << "\n";
exit(1);
}
else
@@ -197,16 +245,87 @@ void recompileCheck(const Settings& settings, int argc, char* argv[])
{
args.push_back(argv[i]);
}
- exit(execute(argv[0], args, settings.verbose));
+ exit(execute(argv[0], args, settings.verbose > 0));
}
}
}
+std::list<std::shared_ptr<Task>> getTasks(const Settings& settings)
+{
+ static std::deque<BuildConfiguration> build_configs;
+ std::list<std::shared_ptr<Task>> tasks;
+ for(int i = 0; i < numConfigFiles; ++i)
+ {
+ std::string path =
+ std::filesystem::path(configFiles[i].file).parent_path();
+ if(settings.verbose > 1)
+ {
+ std::cout << configFiles[i].file << " in path " << path << "\n";
+ }
+ auto configs = configFiles[i].cb();
+ for(const auto& config : configs)
+ {
+ build_configs.push_back(config);
+ const auto& build_config = build_configs.back();
+ std::vector<std::string> objects;
+ auto t = taskFactory(build_config, settings, path);
+ tasks.insert(tasks.end(), t.begin(), t.end());
+ }
+ }
+
+ return tasks;
+}
+
+int configure(int argc, char* argv[],const Settings& settings)
+{
+ auto tasks = getTasks(settings);
+
+ bool needs_cpp{false};
+ bool needs_c{false};
+ bool needs_ar{false};
+ for(const auto& task :tasks)
+ {
+ switch(task->language())
+ {
+ case Language::Auto:
+ std::cerr << "TargetLanguage not deduced!\n";
+ exit(1);
+ break;
+ case Language::C:
+ needs_cpp = false;
+ break;
+ case Language::Cpp:
+ needs_c = true;
+ break;
+ }
+ }
+ std::ofstream istr(configurationFile);
+ istr << "#include \"libcppbuild.h\"\n\n";
+ istr << "const std::map<std::string, std::string>& configuration()\n";
+ istr << "{\n";
+ istr << " static std::map<std::string, std::string> c =\n";
+ istr << " {\n";
+ istr << " { \"builddir\", \"build\" },\n";
+ istr << " { \"host-cc\", \"/usr/bin/gcc\" },\n";
+ istr << " { \"host-cpp\", \"/usr/bin/g++\" },\n";
+ istr << " { \"host-ar\", \"/usr/bin/ar\" },\n";
+ istr << " { \"host-ld\", \"/usr/bin/ld\" },\n";
+ istr << " { \"target-cc\", \"/usr/bin/gcc\" },\n";
+ istr << " { \"target-cpp\", \"/usr/bin/g++\" },\n";
+ istr << " { \"target-ar\", \"/usr/bin/ar\" },\n";
+ istr << " { \"target-ld\", \"/usr/bin/ld\" },\n";
+ istr << " };\n";
+ istr << " return c;\n";
+ istr << "}\n";
+
+ return 0;
+}
+
int main(int argc, char* argv[])
{
Settings settings{};
- settings.builddir = "build/";
+ settings.builddir = getConfiguration("builddir", "build");
settings.parallel_processes =
std::max(1u, std::thread::hardware_concurrency() * 2 - 1);
settings.verbose = 0;
@@ -214,6 +333,11 @@ int main(int argc, char* argv[])
bool write_compilation_database{false};
std::string compilation_database;
+ if(argc > 1 && std::string(argv[1]) == "configure")
+ {
+ return configure(argc, argv, settings);
+ }
+
dg::Options opt;
opt.add("jobs", required_argument, 'j',
@@ -232,7 +356,8 @@ int main(int argc, char* argv[])
});
opt.add("build-dir", required_argument, 'b',
- "Set output directory for build files (default: build).",
+ "Overload output directory for build files (default: '" +
+ settings.builddir + "').",
[&]() {
settings.builddir = optarg;
return 0;
@@ -269,26 +394,7 @@ int main(int argc, char* argv[])
std::filesystem::path builddir(settings.builddir);
std::filesystem::create_directories(builddir);
- std::deque<BuildConfiguration> build_configs;
- std::list<std::shared_ptr<Task>> tasks;
- for(int i = 0; i < numConfigFiles; ++i)
- {
- std::string path =
- std::filesystem::path(configFiles[i].file).parent_path();
- if(settings.verbose > 1)
- {
- std::cout << configFiles[i].file << " in path " << path << "\n";
- }
- auto configs = configFiles[i].cb();
- for(const auto& config : configs)
- {
- build_configs.push_back(config);
- const auto& build_config = build_configs.back();
- std::vector<std::string> objects;
- auto t = taskFactory(build_config, settings, path);
- tasks.insert(tasks.end(), t.begin(), t.end());
- }
- }
+ auto tasks = getTasks(settings);
if(write_compilation_database)
{
@@ -337,7 +443,6 @@ int main(int argc, char* argv[])
if(arg == "clean")
{
std::cout << "Cleaning\n";
- //std::filesystem::remove_all(builddir);
for(auto& task : tasks)
{
if(task->clean() != 0)
@@ -348,6 +453,12 @@ int main(int argc, char* argv[])
return 0;
}
+
+ if(arg == "configure")
+ {
+ std::cerr << "The 'configure' target must be the first argument.\n";
+ return 1;
+ }
}
if(dirtyTasks.empty())