summaryrefslogtreecommitdiffhomepage
path: root/LanguageSettings.cpp
blob: 5eae731a287dac160f0ea5a367751e27fcf2c982 (plain)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
#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>

#include "env.h"
#include "file.h"

namespace fs = std::filesystem;
using namespace std::string_literals;

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

 AR{env_value("AR")}
{
 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 -Wall -O2";
 }

 if (AR.empty()) {
  AR = "ar";
 }
}

std::string LanguageSettings::getCompileCommand(const std::filesystem::path& target,
                                                const std::filesystem::path& source,
                                                const std::filesystem::path& build,
                                                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 + " -I" + p.string();})};

 std::string CXXFLAGS_add{is_dynamic_lib(build) ? " -fvisibility=hidden -fPIC"s : ""s};

 // compile: $(CXX) $(CXXFLAGS) -c $< -o $@
 return fmt::format("{}{}{}{} -c {} -o {}",
                    CXX,
                    CXXFLAGS.empty() ? ""s : (" "s + CXXFLAGS),
                    CXXFLAGS_add,
                    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
{
 std::string input_string{std::accumulate(inputs.begin(), inputs.end(), std::string{},
                                          [](const std::string& sum, const fs::path& p){ return sum + " " + p.string(); })};

 if (is_static_lib(target)) {
  // link: $(AR) rcs libxyz.a x.o y.o z.o
  return fmt::format("{} rcs {}{}",
                     AR,
                     target.string(),
                     input_string);
 } else if (is_executable_target(target) || is_dynamic_lib(target)) {
  // dynamic link: -shared -Wl,-soname,libXXX.so.N -o libXXX.so.N.M.O
  std::string LDFLAGS_add{is_dynamic_lib(target) ? fmt::format(" -shared -Wl,-soname,{}",
                                                               soname_shorter(target.string()).string()) : ""s};

  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; })};

  // link: $(CXX) $(LDFLAGS) $^ $(LDLIBS) $(LIBS) -o $@
  return fmt::format("{}{}{}{}{}{}{} -o {}",
                     CXX,
                     LDFLAGS.empty() ? ""s : (" "s + LDFLAGS),
                     LDFLAGS_add,
                     input_string,
                     LDLIBS.empty() ? ""s : (" "s + LDLIBS),
                     LIBS.empty() ? ""s : (" "s + LIBS),
                     link_libs_string,
                     target.string());
 } else if (is_dynamic_lib_link(target)) {
  // special case for dynamic libs: add links
  if (inputs.size() != 1) {
   throw std::runtime_error("For symlink "s + target.string() + ", can link to exactly one file, found "s + std::to_string(inputs.size()));
  }
  return fmt::format("ln -sf {} {}", inputs[0].filename().string(), target.string());
 } else {
  throw std::runtime_error("No implementation for target type: "s + 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());
}

// TODO:
// variables:
//  CC
//  CFLAGS
//  ARFLAGS
//  AS
//  ASFLAGS