CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
clang_compiler.hpp
1 #ifndef CPPAD_CG_CLANG_COMPILER_INCLUDED
2 #define CPPAD_CG_CLANG_COMPILER_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2014 Ciengis
6  * Copyright (C) 2018 Joao Leal
7  *
8  * CppADCodeGen is distributed under multiple licenses:
9  *
10  * - Eclipse Public License Version 1.0 (EPL1), and
11  * - GNU General Public License Version 3 (GPL3).
12  *
13  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
14  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
15  * ----------------------------------------------------------------------------
16  * Author: Joao Leal
17  */
18 
19 namespace CppAD {
20 namespace cg {
21 
27 template<class Base>
28 class ClangCompiler : public AbstractCCompiler<Base> {
29 protected:
30  std::set<std::string> _bcfiles; // bitcode files
31  std::string _version;
32 public:
33 
34  ClangCompiler(const std::string& clangPath = "/usr/bin/clang") :
35  AbstractCCompiler<Base>(clangPath) {
36 
37  this->_compileFlags.push_back("-O2"); // Optimization level
38  this->_compileLibFlags.push_back("-O2"); // Optimization level
39  this->_compileLibFlags.push_back("-shared"); // Make shared object
40  this->_compileLibFlags.push_back("-rdynamic"); // add all symbols to the dynamic symbol table
41  }
42 
43  ClangCompiler(const ClangCompiler& orig) = delete;
44  ClangCompiler& operator=(const ClangCompiler& rhs) = delete;
45 
46  const std::string& getVersion() {
47  if(_version.empty()) {
48  std::vector<std::string> args {"--version"};
49  std::string output;
50  system::callExecutable(this->_path, args, &output);
51 
52  std::string vv = "version ";
53  size_t is = output.find(vv);
54  if(is == std::string::npos) {
55  throw CGException("Failed to determine Clang version");
56  }
57  is += vv.size();
58  size_t i = is;
59  while (i < output.size() && output[i] != ' ' && output[i] != '\n') {
60  i++;
61  }
62 
63  _version = output.substr(is, i - is);
64  }
65  return _version;
66  }
67 
68  virtual const std::set<std::string>& getBitCodeFiles() const {
69  return _bcfiles;
70  }
71 
72  virtual void generateLLVMBitCode(const std::map<std::string, std::string>& sources,
73  JobTimer* timer = nullptr) {
74  bool posIndepCode = false;
75  this->_compileFlags.push_back("-emit-llvm");
76  try {
77  this->compileSources(sources, posIndepCode, timer, ".bc", this->_bcfiles);
78  } catch (...) {
79  this->_compileFlags.pop_back();
80  throw;
81  }
82  }
83 
89  void buildDynamic(const std::string& library,
90  JobTimer* timer = nullptr) override {
91 
92 #if CPPAD_CG_SYSTEM_APPLE
93  std::string linkerName = "-install_name";
94 #elif CPPAD_CG_SYSTEM_LINUX
95  std::string linkerName = "-soname";
96 #endif
97  std::string linkerFlags = "-Wl," + linkerName + "," + system::filenameFromPath(library);
98  for (size_t i = 0; i < this->_linkFlags.size(); i++)
99  linkerFlags += "," + this->_linkFlags[i];
100 
101  std::vector<std::string> args;
102  args.insert(args.end(), this->_compileLibFlags.begin(), this->_compileLibFlags.end());
103  args.push_back(linkerFlags); // Pass suitable options to linker
104  args.push_back("-o"); // Output file name
105  args.push_back(library); // Output file name
106 
107  for (const std::string& it : this->_ofiles) {
108  args.push_back(it);
109  }
110 
111  if (timer != nullptr) {
112  timer->startingJob("'" + library + "'", JobTimer::COMPILING_DYNAMIC_LIBRARY);
113  } else if (this->_verbose) {
114  std::cout << "building library '" << library << "'" << std::endl;
115  }
116 
117  system::callExecutable(this->_path, args);
118 
119  if (timer != nullptr) {
120  timer->finishedJob();
121  }
122  }
123 
124  void cleanup() override {
125  // clean up
126  for (const std::string& it : _bcfiles) {
127  if (remove(it.c_str()) != 0)
128  std::cerr << "Failed to delete temporary file '" << it << "'" << std::endl;
129  }
130  _bcfiles.clear();
131 
132  // other files and temporary folder
134  }
135 
136  virtual ~ClangCompiler() {
137  cleanup();
138  }
139 
140  static std::vector<std::string> parseVersion(const std::string& version) {
141  auto vv = explode(version, ".");
142  if (vv.size() > 2) {
143  auto vv2 = explode(vv[2], "-");
144  if (vv2.size() > 1) {
145  vv.erase(vv.begin() + 2);
146  vv.insert(vv.begin() + 2, vv2.begin(), vv2.end());
147  }
148  }
149  return vv;
150  }
151 
152 protected:
153 
161  void compileSource(const std::string& source,
162  const std::string& output,
163  bool posIndepCode) override {
164  std::vector<std::string> args;
165  args.push_back("-x");
166  args.push_back("c"); // C source files
167  args.insert(args.end(), this->_compileFlags.begin(), this->_compileFlags.end());
168  args.push_back("-c");
169  args.push_back("-");
170  if (posIndepCode) {
171  args.push_back("-fPIC"); // position-independent code for dynamic linking
172  }
173  args.push_back("-o");
174  args.push_back(output);
175 
176  system::callExecutable(this->_path, args, nullptr, &source);
177  }
178 
179  void compileFile(const std::string& path,
180  const std::string& output,
181  bool posIndepCode) override {
182  std::vector<std::string> args;
183  args.push_back("-x");
184  args.push_back("c"); // C source files
185  args.insert(args.end(), this->_compileFlags.begin(), this->_compileFlags.end());
186  if (posIndepCode) {
187  args.push_back("-fPIC"); // position-independent code for dynamic linking
188  }
189  args.push_back("-c");
190  args.push_back(path);
191  args.push_back("-o");
192  args.push_back(output);
193 
194  system::callExecutable(this->_path, args);
195  }
196 
197 };
198 
199 } // END cg namespace
200 } // END CppAD namespace
201 
202 #endif
void buildDynamic(const std::string &library, JobTimer *timer=nullptr) override
void callExecutable(const std::string &executable, const std::vector< std::string > &args, std::string *stdOutErrMessage=nullptr, const std::string *stdInMessage=nullptr)
void compileSources(const std::map< std::string, std::string > &sources, bool posIndepCode, JobTimer *timer=nullptr) override
void compileSource(const std::string &source, const std::string &output, bool posIndepCode) override
void compileFile(const std::string &path, const std::string &output, bool posIndepCode) override