summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libcppbuild.cc163
-rw-r--r--libcppbuild.h39
-rw-r--r--task.cc19
-rw-r--r--task.h13
-rw-r--r--task_ar.cc16
-rw-r--r--task_cc.cc34
-rw-r--r--task_ld.cc23
-rw-r--r--task_so.cc21
8 files changed, 281 insertions, 47 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())
diff --git a/libcppbuild.h b/libcppbuild.h
index 2aba987..81e7a9e 100644
--- a/libcppbuild.h
+++ b/libcppbuild.h
@@ -3,25 +3,45 @@
#include <string>
#include <vector>
-//#include <source_location>
+#include <map>
enum class TargetType
{
- Auto, // Default - deduce from target name
+ Auto, // Default - deduce from target name and sources extensions
+
Executable,
StaticLibrary,
DynamicLibrary,
+ Object,
+};
+
+enum class Language
+{
+ Auto, // Default - deduce language from source extensions
+
+ C,
+ Cpp,
+ Asm,
+};
+
+enum class OutputSystem
+{
+ Target, // Output for the target system
+ BuildHost, // Internal tool during cross-compilation
};
struct BuildConfiguration
{
TargetType type{TargetType::Auto};
+ Language language{Language::Auto};
+ OutputSystem system{OutputSystem::Target};
std::string target;
- std::vector<std::string> sources;
- std::vector<std::string> depends;
- std::vector<std::string> cxxflags;
- std::vector<std::string> cflags;
- std::vector<std::string> ldflags;
+ std::vector<std::string> sources; // source list
+ std::vector<std::string> depends; // internal dependencies
+ std::vector<std::string> cxxflags; // flags for c++ compiler
+ std::vector<std::string> cflags; // flags for c compiler
+ std::vector<std::string> ldflags; // flags for linker
+ std::vector<std::string> asmflags; // flags for asm translator
};
using BuildConfigurations = std::vector<BuildConfiguration>;
@@ -33,3 +53,8 @@ int reg(const char* location, BuildConfigurations (*cb)());
#define CONCAT_INNER(a, b) a ## b
#define UNIQUE_NAME(base) CONCAT(base, __LINE__)
#define REG(cb) namespace { int UNIQUE_NAME(unique) = reg(__FILE__, cb); }
+
+const std::map<std::string, std::string>& configuration();
+bool hasConfiguration(const std::string& key);
+const std::string& getConfiguration(const std::string& key,
+ const std::string& defaultValue = {});
diff --git a/task.cc b/task.cc
index e5f11aa..928f95d 100644
--- a/task.cc
+++ b/task.cc
@@ -3,8 +3,10 @@
#include <unistd.h>
#include <iostream>
-Task::Task(const std::vector<std::string>& depends)
+Task::Task(const BuildConfiguration& config,
+ const std::vector<std::string>& depends)
: dependsStr(depends)
+ , config(config)
{
}
@@ -84,3 +86,18 @@ State Task::state() const
{
return task_state.load();
}
+
+const BuildConfiguration& Task::buildConfig() const
+{
+ return config;
+}
+
+TargetType Task::targetType() const
+{
+ return target_type;
+}
+
+Language Task::language() const
+{
+ return _language;
+}
diff --git a/task.h b/task.h
index 9c2d622..7ea95fc 100644
--- a/task.h
+++ b/task.h
@@ -7,6 +7,8 @@
#include <list>
#include <memory>
+#include "libcppbuild.h"
+
enum class State
{
Unknown,
@@ -19,7 +21,8 @@ enum class State
class Task
{
public:
- Task(const std::vector<std::string>& depends);
+ Task(const BuildConfiguration& config,
+ const std::vector<std::string>& depends = {});
int registerDepTasks(const std::list<std::shared_ptr<Task>>& tasks);
@@ -33,6 +36,11 @@ public:
virtual std::string toJSON() const { return {}; };
+ const BuildConfiguration& buildConfig() const;
+
+ TargetType targetType() const;
+ Language language() const;
+
protected:
std::atomic<State> task_state{State::Unknown};
virtual int runInner() { return 0; };
@@ -40,4 +48,7 @@ protected:
std::vector<std::string> dependsStr;
std::list<std::shared_ptr<Task>> dependsTasks;
+ const BuildConfiguration& config;
+ TargetType target_type{TargetType::Auto};
+ Language _language{Language::Auto};
};
diff --git a/task_ar.cc b/task_ar.cc
index 58223ad..dca122b 100644
--- a/task_ar.cc
+++ b/task_ar.cc
@@ -41,7 +41,7 @@ TaskAR::TaskAR(const BuildConfiguration& config,
const Settings& settings,
const std::string& target,
const std::vector<std::string>& objects)
- : Task(addPrefix(config.depends, settings))
+ : Task(config, addPrefix(config.depends, settings))
, config(config)
, settings(settings)
{
@@ -63,6 +63,17 @@ TaskAR::TaskAR(const BuildConfiguration& config,
flagsFile = settings.builddir / targetFile.stem();
flagsFile += ".flags";
+
+ target_type = TargetType::StaticLibrary;
+ _language = Language::C;
+ for(const auto& source : config.sources)
+ {
+ std::filesystem::path sourceFile(source);
+ if(sourceFile.extension().string() != ".c")
+ {
+ _language = Language::Cpp;
+ }
+ }
}
bool TaskAR::dirtyInner()
@@ -132,7 +143,8 @@ int TaskAR::runInner()
std::cout << "AR => " << targetFile.string() << "\n";
}
- return execute("/usr/bin/ar", args, settings.verbose > 0);
+ auto tool = getConfiguration("host-ar", "/usr/bin/ar");
+ return execute(tool, args, settings.verbose > 0);
}
int TaskAR::clean()
diff --git a/task_cc.cc b/task_cc.cc
index 6c7e3b7..27b2176 100644
--- a/task_cc.cc
+++ b/task_cc.cc
@@ -85,7 +85,7 @@ std::vector<std::string> readDeps(const std::string& depFile)
TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings,
const std::string& sourceDir, const std::string& source)
- : Task({})
+ : Task(config)
, config(config)
, settings(settings)
, sourceDir(sourceDir)
@@ -101,6 +101,16 @@ TaskCC::TaskCC(const BuildConfiguration& config, const Settings& settings,
flagsFile = settings.builddir / sourceFile.stem();
flagsFile += ".flags";
+
+ target_type = TargetType::Object;
+ if(sourceFile.extension().string() == ".c")
+ {
+ _language = Language::C;
+ }
+ else
+ {
+ _language = Language::Cpp;
+ }
}
bool TaskCC::dirtyInner()
@@ -245,11 +255,17 @@ std::string TaskCC::toJSON() const
std::vector<std::string> TaskCC::flags() const
{
- if(std::string(sourceFile.extension()) == ".c")
+ switch(language())
{
+ case Language::C:
return config.cflags;
+ case Language::Cpp:
+ return config.cxxflags;
+ default:
+ std::cerr << "Unknown CC target type\n";
+ exit(1);
+ break;
}
- return config.cxxflags;
}
std::string TaskCC::flagsString() const
@@ -268,11 +284,17 @@ std::string TaskCC::flagsString() const
std::string TaskCC::compiler() const
{
- if(std::string(sourceFile.extension()) == ".c")
+ switch(language())
{
- return "/usr/bin/gcc";
+ case Language::C:
+ return getConfiguration("host-cc");
+ case Language::Cpp:
+ return getConfiguration("host-cpp");
+ default:
+ std::cerr << "Unknown CC target type\n";
+ exit(1);
+ break;
}
- return "/usr/bin/g++";
}
std::vector<std::string> TaskCC::getCompilerArgs() const
diff --git a/task_ld.cc b/task_ld.cc
index 874ec6d..7bf68ed 100644
--- a/task_ld.cc
+++ b/task_ld.cc
@@ -40,10 +40,12 @@ TaskLD::TaskLD(const BuildConfiguration& config,
const Settings& settings,
const std::string& target,
const std::vector<std::string>& objects)
- : Task(addPrefix(config.depends, settings))
+ : Task(config, addPrefix(config.depends, settings))
, config(config)
, settings(settings)
{
+ target_type = TargetType::Executable;
+
targetFile = settings.builddir;
targetFile /= target;
for(const auto& object : objects)
@@ -62,6 +64,17 @@ TaskLD::TaskLD(const BuildConfiguration& config,
flagsFile = settings.builddir / targetFile.stem();
flagsFile += ".flags";
+
+ target_type = TargetType::Executable;
+ _language = Language::C;
+ for(const auto& source : config.sources)
+ {
+ std::filesystem::path sourceFile(source);
+ if(sourceFile.extension().string() != ".c")
+ {
+ _language = Language::Cpp;
+ }
+ }
}
bool TaskLD::dirtyInner()
@@ -146,7 +159,13 @@ int TaskLD::runInner()
std::cout << "LD => " << targetFile.string() << "\n";
}
- return execute("/usr/bin/g++", args, settings.verbose > 0);
+ auto tool = getConfiguration("host-cpp", "/usr/bin/g++");
+ if(language() == Language::C)
+ {
+ tool = getConfiguration("host-cc", "/usr/bin/gcc");
+ }
+
+ return execute(tool, args, settings.verbose > 0);
}
int TaskLD::clean()
diff --git a/task_so.cc b/task_so.cc
index c484a40..1f5d204 100644
--- a/task_so.cc
+++ b/task_so.cc
@@ -40,7 +40,7 @@ TaskSO::TaskSO(const BuildConfiguration& config,
const Settings& settings,
const std::string& target,
const std::vector<std::string>& objects)
- : Task(addPrefix(config.depends, settings))
+ : Task(config, addPrefix(config.depends, settings))
, config(config)
, settings(settings)
{
@@ -62,6 +62,17 @@ TaskSO::TaskSO(const BuildConfiguration& config,
flagsFile = settings.builddir / targetFile.stem();
flagsFile += ".flags";
+
+ target_type = TargetType::DynamicLibrary;
+ _language = Language::C;
+ for(const auto& source : config.sources)
+ {
+ std::filesystem::path sourceFile(source);
+ if(sourceFile.extension().string() != ".c")
+ {
+ _language = Language::Cpp;
+ }
+ }
}
bool TaskSO::dirtyInner()
@@ -142,7 +153,13 @@ int TaskSO::runInner()
std::cout << "LD => " << targetFile.string() << "\n";
}
- return execute("/usr/bin/g++", args, settings.verbose > 0);
+ auto tool = getConfiguration("host-cpp", "/usr/bin/g++");
+ if(language() == Language::C)
+ {
+ tool = getConfiguration("host-cc", "/usr/bin/gcc");
+ }
+
+ return execute(tool, args, settings.verbose > 0);
}
int TaskSO::clean()