1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
#include "LanguageSettings.h"
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <numeric>
#include <stdexcept>
#include <string>
#include <vector>
#include <fmt/format.h>
#include <libreichwein/stringhelper.h>
namespace fs = std::filesystem;
using namespace std::string_literals;
namespace {
std::string env_value(const std::string& key) {
char* value_ptr{std::getenv(key.c_str())};
if (value_ptr == nullptr) {
return {};
} else {
return value_ptr;
}
}
// returns "" if not found
std::string find_executable(const std::vector<std::string>& list) {
std::vector<std::string> paths {Reichwein::Stringhelper::split(env_value("PATH"), ":")};
for (const auto& i: list) {
for (const auto& j: paths) {
if (fs::exists(j + "/" + i)) {
return i;
}
}
}
return {};
}
}
LanguageSettings::LanguageSettings():
// C++
CXX{env_value("CXX")},
CXXFLAGS{env_value("CXXFLAGS")},
LDFLAGS{env_value("LDFLAGS")},
LDLIBS{env_value("LDLIBS")},
LIBS{env_value("LIBS")}
// C
// CFLAGS
{
std::string _default_compiler(find_executable({"g++", "clang++"}));
if (_default_compiler.empty()) {
throw std::runtime_error("No default C++ compiler found.");
}
// set defaults
if (CXX.empty()) {
CXX = _default_compiler;
}
if (CXXFLAGS.empty()) {
CXXFLAGS = "-std=c++17";
}
}
std::string LanguageSettings::getCompileCommand(const std::filesystem::path& target,
const std::filesystem::path &source,
const std::vector<std::filesystem::path>& includepaths) const
{
std::string includes{std::accumulate(includepaths.begin(), includepaths.end(), std::string{},
[](const std::string& sum, const fs::path& p){ return sum + " " + p.string();})};
// compile: $(CXX) $(CXXFLAGS) -c $< -o $@
return fmt::format("{}{}{} -c {} -o {}",
CXX,
CXXFLAGS.empty() ? ""s : (" "s + CXXFLAGS),
includes,
source.string(),
target.string());
}
std::string LanguageSettings::getLinkCommand(const std::filesystem::path& target,
const std::vector<std::filesystem::path> &inputs,
const std::vector<std::string>& link_libs) const
{
// link: $(CXX) $(LDFLAGS) $^ $(LDLIBS) $(LIBS) -o $@
std::string input_string{std::accumulate(inputs.begin(), inputs.end(), std::string{},
[](const std::string& sum, const fs::path& p){ return sum + " " + p.string(); })};
std::string link_libs_string{std::accumulate(link_libs.begin(), link_libs.end(), std::string(),
[](const std::string& sum, const std::string& i){ return sum + " -l" + i; })};
return fmt::format("{}{}{}{}{}{} -o {}",
CXX,
CXXFLAGS.empty() ? ""s : (" "s + CXXFLAGS),
input_string,
LDLIBS.empty() ? ""s : (" "s + LDLIBS),
LIBS.empty() ? ""s : (" "s + LIBS),
link_libs_string,
target.string());
}
std::string LanguageSettings::getDepCommand(const std::filesystem::path& target, const std::filesystem::path &source) const
{
// g++ -MM -MF <depfile> -c <cppfile>
return fmt::format("{} -MM -MF {} -c {}", CXX, target.string(), source.string());
}
|