summaryrefslogtreecommitdiffhomepage
path: root/LanguageSettings.cpp
blob: 3ded5cf5e27c6b32a9b53d6e4efceb4d47b5404f (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
#include "LanguageSettings.h"

#include <cstdlib>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>

#include <fmt/format.h>

#include <libreichwein/stringhelper.h>

namespace fs = std::filesystem;

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
{
 // compile: $(CXX) $(CXXFLAGS) -c $< -o $@
 return fmt::format("{} {} -c {} -o {}", CXX, CXXFLAGS, 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;
 for (const auto& i: inputs) {
  if (!input_string.empty()) {
   input_string += " ";
  }
  input_string += i.string();
 }

 std::string link_libs_string;
 for (const auto& i: link_libs) {
  if (!link_libs_string.empty()) {
   link_libs_string += " ";
  }
  link_libs_string += "-l" + i;
 }

 return fmt::format("{} {} {} {} {} {} -o {}", CXX, CXXFLAGS, input_string, LDLIBS, 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());
}