summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBent Bisballe Nyeng <deva@aasimon.org>2022-05-27 09:50:35 +0200
committerBent Bisballe Nyeng <deva@aasimon.org>2022-06-09 22:29:32 +0200
commitf5b09df9c88d49c95fd0c0ef7b3670b40634ca5c (patch)
tree3b5e78254b88e5546bf8e041226ad90db1d512c2
parent7a16146600384272baf7fb2fc0fc64f59b17ffe9 (diff)
WIP: automatic externalsexternals
-rw-r--r--ctor.cc1
-rw-r--r--src/configure.cc86
-rw-r--r--src/libctor.h14
-rw-r--r--src/search.cc120
-rw-r--r--src/search.h37
-rw-r--r--test/ctor.cc20
-rw-r--r--test/search_test.cc106
7 files changed, 380 insertions, 4 deletions
diff --git a/ctor.cc b/ctor.cc
index d795ff9..bdae7b8 100644
--- a/ctor.cc
+++ b/ctor.cc
@@ -19,6 +19,7 @@ BuildConfigurations ctorConfigs(const Settings& settings)
"src/externals_manual.cc",
"src/libctor.cc",
"src/rebuild.cc",
+ "src/search.cc",
"src/task.cc",
"src/task_ar.cc",
"src/task_fn.cc",
diff --git a/src/configure.cc b/src/configure.cc
index bc7d3e8..a7e47eb 100644
--- a/src/configure.cc
+++ b/src/configure.cc
@@ -14,6 +14,7 @@
#include "libctor.h"
#include "tasks.h"
#include "rebuild.h"
+#include "search.h"
#include "externals.h"
std::filesystem::path configurationFile("configuration.cc");
@@ -146,6 +147,58 @@ public:
}
};
+int resolv(const Settings& settings, const std::string& name,
+ const ExternalAutomatic& ext, Flags& flags)
+{
+ using namespace std::string_literals;
+
+ flags = ext.flags;
+
+ for(const auto& header : ext.headers)
+ {
+ std::vector<std::string> paths;
+ auto it = external_includedir.find(name);
+ if(it != external_includedir.end())
+ {
+ paths.push_back(it->second);
+ }
+
+ auto res = findHeader(settings, header, paths);
+ if(res.empty())
+ {
+ std::cout << "Header " << header << " required by " << name <<
+ " not found.\n";
+ return 1;
+ }
+ auto flag = "-I"s + res.string();
+ flags.cxxflags.push_back(flag);
+ }
+
+ for(const auto& lib : ext.libs)
+ {
+ std::vector<std::string> paths;
+ auto it = external_libdir.find(name);
+ if(it != external_libdir.end())
+ {
+ paths.push_back(it->second);
+ }
+
+ auto res = findLibrary(settings, lib, paths);
+ if(res.empty())
+ {
+ std::cout << "Library " << lib << " required by " << name <<
+ " not found.\n";
+ return 1;
+ }
+ auto flag = "-L"s + res[0].parent_path().string();
+ flags.ldflags.push_back(flag);
+ flag = "-l"s + lib;
+ flags.ldflags.push_back(flag);
+ }
+
+ return 0;
+}
+
// helper constant for the visitor
template<class> inline constexpr bool always_false_v = false;
@@ -288,7 +341,11 @@ int regenerateCache(const Settings& default_settings,
std::visit([&](auto&& arg)
{
using T = std::decay_t<decltype(arg)>;
- if constexpr (std::is_same_v<T, ExternalManual>)
+ if constexpr (std::is_same_v<T, ExternalAutomatic>)
+ {
+ add_path_args(ext.name);
+ }
+ else if constexpr (std::is_same_v<T, ExternalManual>)
{
add_path_args(ext.name);
}
@@ -298,6 +355,24 @@ int regenerateCache(const Settings& default_settings,
}
}, ext.external);
+ /*
+ if(std::holds_alternative<ExternalAutomatic>(ext.external))
+ {
+ opt.add(ext.name + "-includedir", required_argument, key++,
+ "Set path to " + ext.name + " header file.",
+ [&]() {
+ //X_includedir = optarg;
+ return 0;
+ });
+
+ opt.add(ext.name + "-libdir", required_argument, key++,
+ "Set path to " + ext.name + " libraries.",
+ [&]() {
+ //X_libdir = optarg;
+ return 0;
+ });
+ }
+ */
}
opt.add("help", no_argument, 'h',
@@ -434,6 +509,15 @@ int regenerateCache(const Settings& default_settings,
return ret;
}
}
+ else if(std::holds_alternative<ExternalAutomatic>(ext.external))
+ {
+ if(auto ret = resolv(settings, ext.name,
+ std::get<ExternalAutomatic>(ext.external),
+ resolved_flags))
+ {
+ return ret;
+ }
+ }
else
{
std::cout << "Unknown external type\n";
diff --git a/src/libctor.h b/src/libctor.h
index 14fdf1d..9775085 100644
--- a/src/libctor.h
+++ b/src/libctor.h
@@ -69,7 +69,8 @@ struct Settings
std::string builddir{"build"};
std::size_t parallel_processes{1};
int verbose{0}; // -1: completely silent, 0: normal, 1: verbose, ...
-};
+ std::vector<std::string> include_paths{"/usr/include", "/usr/local/include"};
+ std::vector<std::string> library_paths{"/lib", "/usr/lib", "/usr/local/lib"};};
struct BuildConfiguration;
using GeneratorCb = std::function<int(const std::string& input,
@@ -101,11 +102,20 @@ struct ExternalManual
Flags flags;
};
+// This type will search for the supplied libs and headers, supplied flags
+// will be be used verbatim.
+struct ExternalAutomatic
+{
+ std::vector<std::string> headers;
+ std::vector<std::string> libs;
+ Flags flags;
+};
struct ExternalConfiguration
{
std::string name; // Name for configuration
- std::variant<ExternalManual> external;
+ std::variant<ExternalManual,
+ ExternalAutomatic> external;
};
using ExternalConfigurations = std::vector<ExternalConfiguration>;
diff --git a/src/search.cc b/src/search.cc
new file mode 100644
index 0000000..e33fc04
--- /dev/null
+++ b/src/search.cc
@@ -0,0 +1,120 @@
+#include "search.h"
+
+#include <iostream>
+
+#include "libctor.h"
+
+// https://stackoverflow.com/questions/17939930/finding-out-what-the-gcc-include-path-is
+
+// /usr/include/
+// /usr/local/include
+std::filesystem::path findFile(const Settings& settings,
+ const std::string& needle,
+ const std::vector<std::string>& haystack)
+{
+ if(settings.verbose > 0)
+ {
+ std::cout << "Looking for '" << needle << "'\n";
+ }
+ for(const auto& path : haystack)
+ {
+ std::filesystem::path candidate = std::filesystem::path(path) / needle;
+ if(settings.verbose > 1)
+ {
+ std::cout << " in '" << candidate.string() << "' ... ";
+ }
+ if(std::filesystem::exists(candidate))
+ {
+ if(settings.verbose > 1)
+ {
+ std::cout << "yes\n";
+ }
+ return path;
+ }
+ else
+ {
+ if(settings.verbose > 1)
+ {
+ std::cout << "no\n";
+ }
+ }
+ }
+
+ if(settings.verbose > 0)
+ {
+ std::cout << "Not found.\n";
+ }
+
+ return ""; // not found
+}
+
+std::filesystem::path findHeader(const Settings& settings,
+ const std::string& needle,
+ const std::vector<std::string>& haystack)
+{
+ auto paths = haystack;
+ paths.insert(paths.end(),
+ settings.include_paths.begin(),
+ settings.include_paths.end());
+ return findFile(settings, needle, paths);
+}
+
+std::vector<std::filesystem::path> findBasename(const Settings& settings,
+ const std::string& needle,
+ const std::vector<std::string>& haystack)
+{
+ std::vector<std::filesystem::path> matches;
+ if(settings.verbose > 0)
+ {
+ std::cout << "Looking for basename '" << needle << "'\n";
+ }
+
+ for(const auto& path : haystack)
+ {
+ if(settings.verbose > 1)
+ {
+ std::cout << "Looking in '" << path << "\n";
+ }
+
+ for(const auto& dir_entry : std::filesystem::directory_iterator{path})
+ {
+ if(std::filesystem::is_regular_file(dir_entry))
+ {
+ if(dir_entry.path().stem() == needle)
+ {
+ if(settings.verbose > 1)
+ {
+ std::cout << "Found " << path / dir_entry.path() << "\n";
+ }
+ matches.push_back(path / dir_entry.path());
+ }
+ }
+ }
+ }
+
+ if(matches.empty() && settings.verbose > 0)
+ {
+ std::cout << "Not found.\n";
+ }
+
+ return matches;
+}
+
+std::vector<std::filesystem::path> findLibrary(const Settings& settings,
+ const std::string& needle,
+ const std::vector<std::string>& haystack)
+{
+ using namespace std::string_literals;
+
+ std::string lib = needle;
+ if(!lib.starts_with("lib"))
+ {
+ lib = "lib"s + needle;
+ }
+ auto paths = haystack;
+ paths.insert(paths.end(),
+ settings.library_paths.begin(),
+ settings.library_paths.end());
+ return findBasename(settings, lib, paths);
+}
+
diff --git a/src/search.h b/src/search.h
new file mode 100644
index 0000000..1841978
--- /dev/null
+++ b/src/search.h
@@ -0,0 +1,37 @@
+// -*- c++ -*-
+// Distributed under the BSD 2-Clause License.
+// See accompanying file LICENSE for details.
+#pragma once
+
+#include <filesystem>
+#include <string>
+#include <vector>
+
+struct Settings;
+
+//! Locate file (needle) in the provided search path list (haystack)
+//! The provided settings is used to control verbosity during the search.
+//! \returns a std::filesystem::path pointing to path in which file was found
+//! - empty if not found.
+std::filesystem::path findFile(const Settings& settings,
+ const std::string& needle,
+ const std::vector<std::string>& haystack);
+
+//! Locate header (needle) in the provided search path list (haystack)
+//! The provided settings is used to control verbosity during the search as well
+//! as providing the search paths defaults for headers.
+//! The argument provided haystack is prepended to the one supplied by settings.
+//! \returns a std::filesystem::path pointing to path where the file was found
+//! - empty if not found.
+std::filesystem::path findHeader(const Settings& settings,
+ const std::string& needle,
+ const std::vector<std::string>& haystack);
+
+
+std::vector<std::filesystem::path> findBasename(const Settings& settings,
+ const std::string& needle,
+ const std::vector<std::string>& haystack);
+
+std::vector<std::filesystem::path> findLibrary(const Settings& settings,
+ const std::string& needle,
+ const std::vector<std::string>& haystack);
diff --git a/test/ctor.cc b/test/ctor.cc
index c24ded7..fd97c80 100644
--- a/test/ctor.cc
+++ b/test/ctor.cc
@@ -67,7 +67,9 @@ BuildConfigurations ctorTestConfigs(const Settings& settings)
"../src/build.cc",
"../src/configure.cc",
"../src/execute.cc",
+ "../src/externals_manual.cc",
"../src/rebuild.cc",
+ "../src/search.cc",
"../src/tasks.cc",
"../src/task.cc",
"../src/task_ar.cc",
@@ -76,7 +78,6 @@ BuildConfigurations ctorTestConfigs(const Settings& settings)
"../src/task_ld.cc",
"../src/task_so.cc",
"../src/util.cc",
- "../src/externals_manual.cc",
},
.flags = {
.cxxflags = {
@@ -86,6 +87,23 @@ BuildConfigurations ctorTestConfigs(const Settings& settings)
.ldflags = { "-pthread" },
},
},
+ {
+ .type = TargetType::UnitTest,
+ .target = "search_test",
+ .sources = {
+ "../src/search.cc",
+ "search_test.cc",
+ "testmain.cc",
+ },
+ .flags = {
+ .cxxflags = {
+ "-std=c++20", "-O3", "-s", "-Wall", "-Werror",
+ "-I../src", "-Iuunit",
+ "-DOUTPUT=\"search\"",
+ },
+ .ldflags = { "-pthread" },
+ },
+ },
};
}
}
diff --git a/test/search_test.cc b/test/search_test.cc
new file mode 100644
index 0000000..179fb0e
--- /dev/null
+++ b/test/search_test.cc
@@ -0,0 +1,106 @@
+#include <uunit.h>
+
+#include <string>
+#include <fstream>
+
+#include <search.h>
+#include <libctor.h>
+
+#include "paths.h"
+
+class SearchTest
+ : public uUnit
+{
+public:
+ SearchTest()
+ {
+ uTEST(SearchTest::test_include);
+ uTEST(SearchTest::test_lib);
+ }
+
+ void test_include()
+ {
+ using namespace std::string_literals;
+
+ constexpr auto verb = -1;
+
+ auto src = paths::top_srcdir / "src";
+ auto tmp = std::filesystem::temp_directory_path();
+
+ { // system
+ Settings settings{.verbose = verb}; // instantiate with default paths set
+ auto result = findHeader(settings, "stdio.h", {});
+ uASSERT_EQUAL("/usr/include"s, result.string());
+ }
+
+ { // libctor.h in src folder
+ Settings settings{.verbose = verb}; // instantiate with default paths set
+ auto result = findHeader(settings, "libctor.h", { src.string() });
+ uASSERT_EQUAL(src, result);
+ }
+
+ { // src/libctor.h in topsrc folder (ie. path with '/')
+ Settings settings{.verbose = verb}; // instantiate with default paths set
+ auto result = findHeader(settings, "src/libctor.h",
+ { paths::top_srcdir.string() });
+ uASSERT_EQUAL(paths::top_srcdir, result);
+ }
+
+ { // libctor.h in src folder over one in temp folder (system)
+ Settings settings{.verbose = verb}; // instantiate with default paths set
+ settings.include_paths = { tmp.string() };
+ auto tmpfile = tmp / "libctor.h";
+ { // create /tmp/libctor.h file
+ std::ofstream of(tmpfile.string());
+ of << "/* nop */";
+ }
+ auto result = findHeader(settings, "libctor.h", { src.string() });
+ std::filesystem::remove(tmpfile);
+ uASSERT_EQUAL(src, result);
+ }
+
+ { // libctor.h in temp folder over one in src folder (local prio)
+ Settings settings{.verbose = verb}; // instantiate with default paths set
+ settings.include_paths = {}; // remove system search paths
+ auto tmpfile = tmp / "libctor.h";
+ { // create /tmp/libctor.h file
+ std::ofstream of(tmpfile.string());
+ of << "/* nop */";
+ }
+ auto result = findHeader(settings, "libctor.h",
+ { tmp.string(), src.string() });
+ std::filesystem::remove(tmpfile);
+ uASSERT_EQUAL(tmp, result);
+ }
+
+ { // not found
+ Settings settings{.verbose = verb};
+ settings.include_paths = {}; // remove system search paths
+ auto result = findHeader(settings, "no_such_file.h", {});
+ uASSERT(result.empty());
+ }
+ }
+
+ void test_lib()
+ {
+ using namespace std::string_literals;
+
+ constexpr auto verb = 2;
+
+ auto src = paths::top_srcdir / "src";
+ auto tmp = std::filesystem::temp_directory_path();
+
+ { // system
+ Settings settings{.verbose = verb}; // instantiate with default paths set
+ auto result = findLibrary(settings, "ffi", {});
+ for(auto f : result)
+ {
+ std::cout << f << "\n";
+ }
+ uASSERT_EQUAL("/usr/lib/libffi.so"s, result[0].string());
+ }
+ }
+};
+
+// Registers the fixture into the 'registry'
+static SearchTest test;