-
Notifications
You must be signed in to change notification settings - Fork 314
Expand file tree
/
Copy pathCIFactory.cpp
More file actions
1287 lines (1124 loc) · 49.7 KB
/
Copy pathCIFactory.cpp
File metadata and controls
1287 lines (1124 loc) · 49.7 KB
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// author: Axel Naumann <axel@cern.ch>
//
// This file is dual-licensed: you can choose to license it under the University
// of Illinois Open Source License or the GNU Lesser General Public License. See
// LICENSE.TXT for details.
//------------------------------------------------------------------------------
#include "ClingUtils.h"
#include "DeclCollector.h"
#include <cling-compiledata.h>
#include "cling/Interpreter/CIFactory.h"
#include "cling/Interpreter/InvocationOptions.h"
#include "cling/Utils/Output.h"
#include "cling/Utils/Paths.h"
#include "cling/Utils/Platform.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Basic/Version.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/Frontend/MultiplexConsumer.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/VerifyDiagnosticConsumer.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Serialization/ASTReader.h"
#include "clang/Serialization/ASTWriter.h"
#include "clang/Serialization/SerializationDiagnostic.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetOptions.h"
#include <cstdio>
#include <ctime>
#include <memory>
using namespace clang;
using namespace cling;
namespace {
static constexpr unsigned CxxStdCompiledWith() {
// The value of __cplusplus in GCC < 5.0 (e.g. 4.9.3) when
// either -std=c++1y or -std=c++14 is specified is 201300L, which fails
// the test for C++14 or more (201402L) as previously specified.
// I would claim that the check should be relaxed to:
#if __cplusplus > 201402L
return 17;
#elif __cplusplus > 201103L || (defined(LLVM_ON_WIN32) && _MSC_VER >= 1900)
return 14;
#elif __cplusplus >= 201103L
return 11;
#else
#error "Unknown __cplusplus version"
#endif
}
// This function isn't referenced outside its translation unit, but it
// can't use the "static" keyword because its address is used for
// GetMainExecutable (since some platforms don't support taking the
// address of main, and some platforms can't implement GetMainExecutable
// without being given the address of a function in the main executable).
std::string GetExecutablePath(const char *Argv0) {
// This just needs to be some symbol in the binary; C++ doesn't
// allow taking the address of ::main however.
void *MainAddr = (void*) intptr_t(GetExecutablePath);
return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
}
class AdditionalArgList {
typedef std::vector< std::pair<const char*,std::string> > container_t;
container_t m_Saved;
public:
void addArgument(const char* arg, std::string value = std::string()) {
m_Saved.push_back(std::make_pair(arg,std::move(value)));
}
container_t::const_iterator begin() const { return m_Saved.begin(); }
container_t::const_iterator end() const { return m_Saved.end(); }
bool empty() const { return m_Saved.empty(); }
};
#ifndef _MSC_VER
static void ReadCompilerIncludePaths(const char* Compiler,
llvm::SmallVectorImpl<char>& Buf,
AdditionalArgList& Args,
bool Verbose) {
std::string CppInclQuery("LC_ALL=C ");
CppInclQuery.append(Compiler);
CppInclQuery.append(" -xc++ -E -v /dev/null 2>&1 >/dev/null "
"| awk '/^#include </,/^End of search"
"/{if (!/^#include </ && !/^End of search/){ print }}' "
"| GREP_OPTIONS= grep -E \"(c|g)\\+\\+\"");
if (Verbose)
cling::log() << "Looking for C++ headers with:\n " << CppInclQuery << "\n";
if (FILE *PF = ::popen(CppInclQuery.c_str(), "r")) {
Buf.resize(Buf.capacity_in_bytes());
while (fgets(&Buf[0], Buf.capacity_in_bytes(), PF) && Buf[0]) {
llvm::StringRef Path(&Buf[0]);
// Skip leading and trailing whitespace
Path = Path.trim();
if (!Path.empty()) {
if (!llvm::sys::fs::is_directory(Path)) {
if (Verbose)
cling::utils::LogNonExistantDirectory(Path);
}
else
Args.addArgument("-cxx-isystem", Path.str());
}
}
::pclose(PF);
} else {
::perror("popen failure");
// Don't be overly verbose, we already printed the command
if (!Verbose)
cling::errs() << " for '" << CppInclQuery << "'\n";
}
// Return the query in Buf on failure
if (Args.empty()) {
Buf.resize(0);
Buf.insert(Buf.begin(), CppInclQuery.begin(), CppInclQuery.end());
} else if (Verbose) {
cling::log() << "Found:\n";
for (const auto& Arg : Args)
cling::log() << " " << Arg.second << "\n";
}
}
static bool AddCxxPaths(llvm::StringRef PathStr, AdditionalArgList& Args,
bool Verbose) {
if (Verbose)
cling::log() << "Looking for C++ headers in \"" << PathStr << "\"\n";
llvm::SmallVector<llvm::StringRef, 6> Paths;
if (!utils::SplitPaths(PathStr, Paths, utils::kFailNonExistant,
platform::kEnvDelim, Verbose))
return false;
if (Verbose) {
cling::log() << "Found:\n";
for (llvm::StringRef Path : Paths)
cling::log() << " " << Path << "\n";
}
for (llvm::StringRef Path : Paths)
Args.addArgument("-cxx-isystem", Path.str());
return true;
}
#endif
static std::string getResourceDir(const char* llvmdir) {
if (!llvmdir) {
// FIXME: The first arg really does need to be argv[0] on FreeBSD.
//
// Note: The second arg is not used for Apple, FreeBSD, Linux,
// or cygwin, and can only be used on systems which support
// the use of dladdr().
//
// Note: On linux and cygwin this uses /proc/self/exe to find the path
// Note: On Apple it uses _NSGetExecutablePath().
// Note: On FreeBSD it uses getprogpath().
// Note: Otherwise it uses dladdr().
//
return CompilerInvocation::GetResourcesPath(
"cling", (void*)intptr_t(GetExecutablePath));
} else {
std::string resourcePath;
llvm::SmallString<512> tmp(llvmdir);
llvm::sys::path::append(tmp, "lib", "clang", CLANG_VERSION_STRING);
resourcePath.assign(&tmp[0], tmp.size());
return resourcePath;
}
}
///\brief Adds standard library -I used by whatever compiler is found in PATH.
static void AddHostArguments(llvm::StringRef clingBin,
std::vector<const char*>& args,
const char* llvmdir, const CompilerOptions& opts) {
static AdditionalArgList sArguments;
if (sArguments.empty()) {
const bool Verbose = opts.Verbose;
#ifdef _MSC_VER
// When built with access to the proper Windows APIs, try to actually find
// the correct include paths first. Init for UnivSDK.empty check below.
std::string VSDir, WinSDK,
UnivSDK(opts.NoBuiltinInc ? "" : CLING_UCRT_VERSION);
if (platform::GetVisualStudioDirs(VSDir,
opts.NoBuiltinInc ? nullptr : &WinSDK,
opts.NoBuiltinInc ? nullptr : &UnivSDK,
Verbose)) {
if (!opts.NoCXXInc) {
// The Visual Studio 2017 path is very different than the previous
// versions (see also GetVisualStudioDirs() in PlatformWin.cpp)
const std::string VSIncl = VSDir + "\\include";
if (Verbose)
cling::log() << "Adding VisualStudio SDK: '" << VSIncl << "'\n";
sArguments.addArgument("-I", std::move(VSIncl));
}
if (!opts.NoBuiltinInc) {
if (!WinSDK.empty()) {
WinSDK.append("\\include");
if (Verbose)
cling::log() << "Adding Windows SDK: '" << WinSDK << "'\n";
sArguments.addArgument("-I", std::move(WinSDK));
} else {
// Since Visual Studio 2017, this is not valid anymore...
VSDir.append("\\VC\\PlatformSDK\\Include");
if (Verbose)
cling::log() << "Adding Platform SDK: '" << VSDir << "'\n";
sArguments.addArgument("-I", std::move(VSDir));
}
}
}
#if LLVM_MSC_PREREQ(1900)
if (!UnivSDK.empty()) {
if (Verbose)
cling::log() << "Adding UniversalCRT SDK: '" << UnivSDK << "'\n";
sArguments.addArgument("-I", std::move(UnivSDK));
}
#endif
// Windows headers use '__declspec(dllexport) __cdecl' for most funcs
// causing a lot of warnings for different redeclarations (eg. coming from
// the test suite).
// Do not warn about such cases.
sArguments.addArgument("-Wno-dll-attribute-on-redeclaration");
sArguments.addArgument("-Wno-inconsistent-dllimport");
// Assume Windows.h might be included, and don't spew a ton of warnings
sArguments.addArgument("-Wno-ignored-attributes");
sArguments.addArgument("-Wno-nonportable-include-path");
sArguments.addArgument("-Wno-microsoft-enum-value");
sArguments.addArgument("-Wno-expansion-to-defined");
// silent many warnings (mostly during ROOT compilation)
sArguments.addArgument("-Wno-constant-conversion");
sArguments.addArgument("-Wno-unknown-escape-sequence");
sArguments.addArgument("-Wno-microsoft-unqualified-friend");
sArguments.addArgument("-Wno-deprecated-declarations");
//sArguments.addArgument("-fno-threadsafe-statics");
//sArguments.addArgument("-Wno-dllimport-static-field-def");
//sArguments.addArgument("-Wno-microsoft-template");
#else // _MSC_VER
// Skip LLVM_CXX execution if -nostdinc++ was provided.
if (!opts.NoCXXInc) {
// Need sArguments.empty as a check condition later
assert(sArguments.empty() && "Arguments not empty");
SmallString<2048> buffer;
#ifdef _LIBCPP_VERSION
// Try to use a version of clang that is located next to cling
// in case cling was built with a new/custom libc++
std::string clang = llvm::sys::path::parent_path(clingBin);
buffer.assign(clang);
llvm::sys::path::append(buffer, "clang");
clang.assign(&buffer[0], buffer.size());
if (llvm::sys::fs::is_regular_file(clang)) {
if (!opts.StdLib) {
#if defined(_LIBCPP_VERSION)
clang.append(" -stdlib=libc++");
#elif defined(__GLIBCXX__)
clang.append(" -stdlib=libstdc++");
#endif
}
ReadCompilerIncludePaths(clang.c_str(), buffer, sArguments, Verbose);
}
#endif // _LIBCPP_VERSION
// First try the relative path 'g++'
#ifdef CLING_CXX_RLTV
if (sArguments.empty())
ReadCompilerIncludePaths(CLING_CXX_RLTV, buffer, sArguments, Verbose);
#endif
// Then try the include directory cling was built with
#ifdef CLING_CXX_INCL
if (sArguments.empty())
AddCxxPaths(CLING_CXX_INCL, sArguments, Verbose);
#endif
// Finally try the absolute path i.e.: '/usr/bin/g++'
#ifdef CLING_CXX_PATH
if (sArguments.empty())
ReadCompilerIncludePaths(CLING_CXX_PATH, buffer, sArguments, Verbose);
#endif
if (sArguments.empty()) {
// buffer is a copy of the query string that failed
cling::errs() << "ERROR in cling::CIFactory::createCI(): cannot extract"
" standard library include paths!\n";
#if defined(CLING_CXX_PATH) || defined(CLING_CXX_RLTV)
// Only when ReadCompilerIncludePaths called do we have the command
// Verbose has already printed the command
if (!Verbose)
cling::errs() << "Invoking:\n " << buffer.c_str() << "\n";
cling::errs() << "Results was:\n";
const int ExitCode = system(buffer.c_str());
cling::errs() << "With exit code " << ExitCode << "\n";
#elif !defined(CLING_CXX_INCL)
// Technically a valid configuration that just wants to use libClangs
// internal header detection, but for now give a hint about why.
cling::errs() << "CLING_CXX_INCL, CLING_CXX_PATH, and CLING_CXX_RLTV"
" are undefined, there was probably an error during"
" configuration.\n";
#endif
} else
sArguments.addArgument("-nostdinc++");
}
#if defined(__APPLE__)
if (!opts.NoBuiltinInc && !opts.SysRoot) {
std::string sysRoot;
if (platform::GetISysRoot(sysRoot, Verbose)) {
if (Verbose)
cling::log() << "Using SDK \"" << sysRoot << "\"\n";
sArguments.addArgument("-isysroot", std::move(sysRoot));
}
}
#endif // __APPLE__
#endif // _MSC_VER
if (!opts.ResourceDir && !opts.NoBuiltinInc) {
std::string resourcePath = getResourceDir(llvmdir);
// FIXME: Handle cases, where the cling is part of a library/framework.
// There we can't rely on the find executable logic.
if (!llvm::sys::fs::is_directory(resourcePath)) {
cling::errs()
<< "ERROR in cling::CIFactory::createCI():\n resource directory "
<< resourcePath << " not found!\n";
resourcePath = "";
} else {
sArguments.addArgument("-resource-dir", std::move(resourcePath));
}
}
}
for (auto& arg : sArguments) {
args.push_back(arg.first);
args.push_back(arg.second.c_str());
}
}
static void SetClingCustomLangOpts(LangOptions& Opts,
const CompilerOptions& CompilerOpts) {
Opts.EmitAllDecls = 0; // Otherwise if PCH attached will codegen all decls.
#ifdef _MSC_VER
#ifdef _DEBUG
// FIXME: This requires bufferoverflowu.lib, but adding:
// #pragma comment(lib, "bufferoverflowu.lib") still gives errors!
// Opts.setStackProtector(clang::LangOptions::SSPStrong);
#endif // _DEBUG
#ifdef _CPPRTTI
Opts.RTTIData = 1;
#else
Opts.RTTIData = 0;
#endif // _CPPRTTI
Opts.Trigraphs = 0;
Opts.setDefaultCallingConv(clang::LangOptions::DCC_CDecl);
#else // !_MSC_VER
Opts.Trigraphs = 1;
// Opts.RTTIData = 1;
// Opts.DefaultCallingConventions = 1;
// Opts.StackProtector = 0;
#endif // _MSC_VER
Opts.Exceptions = 1;
if (Opts.CPlusPlus) {
Opts.CXXExceptions = 1;
}
//Opts.Modules = 1;
// See test/CodeUnloading/PCH/VTables.cpp which implicitly compares clang
// to cling lang options. They should be the same, we should not have to
// give extra lang options to their invocations on any platform.
// Except -fexceptions -fcxx-exceptions.
Opts.Deprecated = 1;
#ifdef __APPLE__
Opts.Blocks = 1;
Opts.MathErrno = 0;
#endif
#ifdef _REENTRANT
Opts.POSIXThreads = 1;
#endif
#ifdef __FAST_MATH__
Opts.FastMath = 1;
#endif
if (CompilerOpts.DefaultLanguage(&Opts)) {
#ifdef __STRICT_ANSI__
Opts.GNUMode = 0;
#else
Opts.GNUMode = 1;
#endif
Opts.GNUKeywords = 0;
}
}
static void SetClingTargetLangOpts(LangOptions& Opts,
const TargetInfo& Target,
const CompilerOptions& CompilerOpts) {
if (Target.getTriple().getOS() == llvm::Triple::Win32) {
Opts.MicrosoftExt = 1;
#ifdef _MSC_VER
Opts.MSCompatibilityVersion = (_MSC_VER * 100000);
#endif
// Should fix http://llvm.org/bugs/show_bug.cgi?id=10528
Opts.DelayedTemplateParsing = 1;
} else {
Opts.MicrosoftExt = 0;
}
if (CompilerOpts.DefaultLanguage(&Opts)) {
#if _GLIBCXX_USE_FLOAT128
// We are compiling with libstdc++ with __float128 enabled.
if (!Target.hasFloat128Type()) {
// clang currently supports native __float128 only on few targets, and
// this target does not have it. The most visible consequence of this is
// a specialization
// __is_floating_point_helper<__float128>
// in include/c++/6.3.0/type_traits:344 that clang then rejects. The
// specialization is protected by !if _GLIBCXX_USE_FLOAT128 (which is
// unconditionally set in c++config.h) and #if !__STRICT_ANSI__. Tweak
// the latter by disabling GNUMode:
cling::errs()
<< "Disabling gnu++: "
"clang has no __float128 support on this target!\n";
Opts.GNUMode = 0;
}
#endif //_GLIBCXX_USE_FLOAT128
}
}
// This must be a copy of clang::getClangToolFullVersion(). Luckily
// we'll notice quickly if it ever changes! :-)
static std::string CopyOfClanggetClangToolFullVersion(StringRef ToolName) {
cling::stdstrstream OS;
#ifdef CLANG_VENDOR
OS << CLANG_VENDOR;
#endif
OS << ToolName << " version " CLANG_VERSION_STRING " "
<< getClangFullRepositoryVersion();
// If vendor supplied, include the base LLVM version as well.
#ifdef CLANG_VENDOR
OS << " (based on LLVM " << PACKAGE_VERSION << ")";
#endif
return OS.str();
}
///\brief Check the compile-time clang version vs the run-time clang version,
/// a mismatch could cause havoc. Reports if clang versions differ.
static void CheckClangCompatibility() {
if (clang::getClangToolFullVersion("cling")
!= CopyOfClanggetClangToolFullVersion("cling"))
cling::errs()
<< "Warning in cling::CIFactory::createCI():\n "
"Using incompatible clang library! "
"Please use the one provided by cling!\n";
return;
}
/// \brief Retrieves the clang CC1 specific flags out of the compilation's
/// jobs. Returns NULL on error.
static const llvm::opt::ArgStringList*
GetCC1Arguments(clang::driver::Compilation *Compilation,
clang::DiagnosticsEngine* = nullptr) {
// We expect to get back exactly one Command job, if we didn't something
// failed. Extract that job from the Compilation.
const clang::driver::JobList &Jobs = Compilation->getJobs();
if (!Jobs.size() || !isa<clang::driver::Command>(*Jobs.begin())) {
// diagnose this better...
cling::errs() << "No Command jobs were built.\n";
return nullptr;
}
// The one job we find should be to invoke clang again.
const clang::driver::Command *Cmd
= cast<clang::driver::Command>(&(*Jobs.begin()));
if (llvm::StringRef(Cmd->getCreator().getName()) != "clang") {
// diagnose this better...
cling::errs() << "Clang wasn't the first job.\n";
return nullptr;
}
return &Cmd->getArguments();
}
/// \brief Splits the given environment variable by the path separator.
/// Can be used to extract the paths from LD_LIBRARY_PATH.
static SmallVector<StringRef, 4> getPathsFromEnv(const char* EnvVar) {
if (!EnvVar) return {};
SmallVector<StringRef, 4> Paths;
StringRef(EnvVar).split(Paths, ':', -1, false);
return Paths;
}
/// \brief Prepares a file path for string comparison with another file path.
/// This easily be tricked by a malicious user with hardlinking directories
/// and so on, but for a comparison in good faith this should be enough.
static std::string normalizePath(StringRef path) {
SmallVector<char, 256> AbsolutePath, Result;
AbsolutePath.insert(AbsolutePath.begin(), path.begin(), path.end());
llvm::sys::fs::make_absolute(AbsolutePath);
llvm::sys::fs::real_path(AbsolutePath, Result, true);
return llvm::Twine(Result).str();
}
/// \brief Adds all the paths to the prebuilt module paths of the given
/// HeaderSearchOptions.
static void addPrebuiltModulePaths(clang::HeaderSearchOptions& Opts,
const SmallVectorImpl<StringRef>& Paths) {
for (StringRef ModulePath : Paths) {
// FIXME: If we have a prebuilt module path that is equal to our module
// cache we fail to compile the clang builtin modules for some reason.
// This can't be reproduced in clang, so I assume we have some strange
// error in our interpreter setup where this is causing errors (or maybe
// clang is doing the same check in some hidden place).
// The error looks like this:
// .../include/stddef.h error: unknown type name '__PTRDIFF_TYPE__'
// typedef __PTRDIFF_TYPE__ ptrdiff_t;
// <similar follow up errors>
// For now it is fixed by just checking those two paths are not identical.
if (normalizePath(ModulePath) != normalizePath(Opts.ModuleCachePath)) {
Opts.AddPrebuiltModulePath(ModulePath);
}
}
}
#if defined(_MSC_VER) || defined(NDEBUG)
static void stringifyPreprocSetting(PreprocessorOptions& PPOpts,
const char* Name, int Val) {
smallstream Strm;
Strm << Name << "=" << Val;
PPOpts.addMacroDef(Strm.str());
}
#define STRINGIFY_PREPROC_SETTING(PP, name) \
stringifyPreprocSetting(PP, #name, name)
#endif
/// Set cling's preprocessor defines to match the cling binary.
static void SetPreprocessorFromBinary(PreprocessorOptions& PPOpts) {
#ifdef _MSC_VER
// FIXME: Stay consistent with the _HAS_EXCEPTIONS flag settings in SetClingCustomLangOpts
// STRINGIFY_PREPROC_SETTING(PPOpts, _HAS_EXCEPTIONS);
#ifdef _DEBUG
STRINGIFY_PREPROC_SETTING(PPOpts, _DEBUG);
#endif
#endif
#ifdef NDEBUG
STRINGIFY_PREPROC_SETTING(PPOpts, NDEBUG);
#endif
// Since cling, uses clang instead, macros always sees __CLANG__ defined
// In addition, clang also defined __GNUC__, we add the following two macros
// to allow scripts, and more important, dictionary generation to know which
// of the two is the underlying compiler.
#ifdef __clang__
PPOpts.addMacroDef("__CLING__clang__=" ClingStringify(__clang__));
#elif defined(__GNUC__)
PPOpts.addMacroDef("__CLING__GNUC__=" ClingStringify(__GNUC__));
PPOpts.addMacroDef("__CLING__GNUC_MINOR__=" ClingStringify(__GNUC_MINOR__));
#elif defined(_MSC_VER)
PPOpts.addMacroDef("__CLING__MSVC__=" ClingStringify(_MSC_VER));
#endif
// https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
#ifdef _GLIBCXX_USE_CXX11_ABI
PPOpts.addMacroDef("_GLIBCXX_USE_CXX11_ABI="
ClingStringify(_GLIBCXX_USE_CXX11_ABI));
#endif
#if defined(LLVM_ON_WIN32)
PPOpts.addMacroDef("CLING_EXPORT=__declspec(dllimport)");
#else
PPOpts.addMacroDef("CLING_EXPORT=");
#endif
}
/// Set target-specific preprocessor defines.
static void SetPreprocessorFromTarget(PreprocessorOptions& PPOpts,
const llvm::Triple& TTriple) {
if (TTriple.getEnvironment() == llvm::Triple::Cygnus) {
// clang "forgets" the basic arch part needed by winnt.h:
if (TTriple.getArch() == llvm::Triple::x86) {
PPOpts.addMacroDef("_X86_=1");
} else if (TTriple.getArch() == llvm::Triple::x86_64) {
PPOpts.addMacroDef("__x86_64=1");
} else {
cling::errs() << "Warning in cling::CIFactory::createCI():\n"
"unhandled target architecture "
<< TTriple.getArchName() << '\n';
}
}
}
template <class CONTAINER>
static void insertBehind(CONTAINER& To, const CONTAINER& From) {
To.insert(To.end(), From.begin(), From.end());
}
static void AddRuntimeIncludePaths(llvm::StringRef ClingBin,
clang::HeaderSearchOptions& HOpts) {
if (HOpts.Verbose)
cling::log() << "Adding runtime include paths:\n";
// Add configuration paths to interpreter's include files.
#ifdef CLING_INCLUDE_PATHS
if (HOpts.Verbose)
cling::log() << " \"" CLING_INCLUDE_PATHS "\"\n";
utils::AddIncludePaths(CLING_INCLUDE_PATHS, HOpts);
#endif
llvm::SmallString<512> P(ClingBin);
if (!P.empty()) {
// Remove /cling from foo/bin/clang
llvm::StringRef ExeIncl = llvm::sys::path::parent_path(P);
// Remove /bin from foo/bin
ExeIncl = llvm::sys::path::parent_path(ExeIncl);
P.resize(ExeIncl.size());
// Get foo/include
llvm::sys::path::append(P, "include");
if (llvm::sys::fs::is_directory(P.str())) {
utils::AddIncludePaths(P.str(), HOpts, nullptr);
llvm::sys::path::append(P, "clang");
if (!llvm::sys::fs::is_directory(P.str())) {
// LLVM is not installed. Try resolving clang from its usual location.
llvm::SmallString<512> PParent = llvm::sys::path::parent_path(P);
P = PParent;
llvm::sys::path::append(P, "..", "tools", "clang", "include");
if (llvm::sys::fs::is_directory(P.str()))
utils::AddIncludePaths(P.str(), HOpts, nullptr);
}
}
}
}
static llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
SetupDiagnostics(DiagnosticOptions& DiagOpts) {
// The compiler invocation is the owner of the diagnostic options.
// Everything else points to them.
llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs> DiagIDs(new DiagnosticIDs());
std::unique_ptr<TextDiagnosticPrinter>
DiagnosticPrinter(new TextDiagnosticPrinter(cling::errs(), &DiagOpts));
llvm::IntrusiveRefCntPtr<DiagnosticsEngine>
Diags(new DiagnosticsEngine(DiagIDs, &DiagOpts,
DiagnosticPrinter.get(), /*Owns it*/ true));
DiagnosticPrinter.release();
return Diags;
}
static bool
SetupCompiler(CompilerInstance* CI, const CompilerOptions& CompilerOpts,
bool Lang = true, bool Targ = true) {
LangOptions& LangOpts = CI->getLangOpts();
// Set the language options, which cling needs.
// This may have already been done via a precompiled header
if (Lang)
SetClingCustomLangOpts(LangOpts, CompilerOpts);
PreprocessorOptions& PPOpts = CI->getInvocation().getPreprocessorOpts();
SetPreprocessorFromBinary(PPOpts);
// Sanity check that clang delivered the language standard requested
if (CompilerOpts.DefaultLanguage(&LangOpts)) {
switch (CxxStdCompiledWith()) {
case 17: assert(LangOpts.CPlusPlus1z && "Language version mismatch");
// fall-through!
case 14: assert(LangOpts.CPlusPlus14 && "Language version mismatch");
// fall-through!
case 11: assert(LangOpts.CPlusPlus11 && "Language version mismatch");
break;
default: assert(false && "You have an unhandled C++ standard!");
}
}
PPOpts.addMacroDef("__CLING__");
if (LangOpts.CPlusPlus11 == 1)
PPOpts.addMacroDef("__CLING__CXX11");
if (LangOpts.CPlusPlus14 == 1)
PPOpts.addMacroDef("__CLING__CXX14");
if (CI->getDiagnostics().hasErrorOccurred()) {
cling::errs() << "Compiler error too early in initialization.\n";
return false;
}
CI->setTarget(TargetInfo::CreateTargetInfo(CI->getDiagnostics(),
CI->getInvocation().TargetOpts));
if (!CI->hasTarget()) {
cling::errs() << "Could not determine compiler target.\n";
return false;
}
CI->getTarget().adjust(LangOpts);
// This may have already been done via a precompiled header
if (Targ)
SetClingTargetLangOpts(LangOpts, CI->getTarget(), CompilerOpts);
SetPreprocessorFromTarget(PPOpts, CI->getTarget().getTriple());
return true;
}
class ActionScan {
std::set<const clang::driver::Action*> m_Visited;
llvm::SmallVector<clang::driver::Action::ActionClass, 2> m_Kinds;
bool find (const clang::driver::Action* A) {
if (A && !m_Visited.count(A)) {
if (std::find(m_Kinds.begin(), m_Kinds.end(), A->getKind()) !=
m_Kinds.end())
return true;
m_Visited.insert(A);
return find(*A->input_begin());
}
return false;
}
public:
ActionScan(clang::driver::Action::ActionClass a, int b = -1) {
m_Kinds.push_back(a);
if (b != -1)
m_Kinds.push_back(clang::driver::Action::ActionClass(b));
}
bool find (clang::driver::Compilation* C) {
for (clang::driver::Action* A : C->getActions()) {
if (find(A))
return true;
}
return false;
}
};
static void HandlePlugins(CompilerInstance& CI,
std::vector<std::unique_ptr<ASTConsumer>>& Consumers) {
// Copied from Frontend/FrontendAction.cpp.
// FIXME: Remove when we switch to the new cling driver.
for (const std::string& Path : CI.getFrontendOpts().Plugins) {
std::string Error;
if (llvm::sys::DynamicLibrary::LoadLibraryPermanently(Path.c_str(),
&Error))
CI.getDiagnostics().Report(clang::diag::err_fe_unable_to_load_plugin)
<< Path << Error;
}
// If there are no registered plugins we don't need to wrap the consumer
if (FrontendPluginRegistry::begin() == FrontendPluginRegistry::end())
return;
for (auto it = clang::FrontendPluginRegistry::begin(),
ie = clang::FrontendPluginRegistry::end();
it != ie; ++it) {
std::unique_ptr<clang::PluginASTAction> P(it->instantiate());
if (P->ParseArgs(CI, CI.getFrontendOpts().PluginArgs[it->getName()])) {
std::unique_ptr<ASTConsumer> PluginConsumer
= P->CreateASTConsumer(CI, /*InputFile*/ "");
Consumers.push_back(std::move(PluginConsumer));
}
assert(P->getActionType() != clang::PluginASTAction::ReplaceAction);
}
}
static CompilerInstance*
createCIImpl(std::unique_ptr<llvm::MemoryBuffer> Buffer,
const CompilerOptions& COpts, const char* LLVMDir,
std::unique_ptr<clang::ASTConsumer> customConsumer, bool OnlyLex,
bool HasInput = false) {
// Follow clang -v convention of printing version on first line
if (COpts.Verbose)
cling::log() << "cling version " << ClingStringify(CLING_VERSION) << '\n';
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargets();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllTargetMCs();
// Create an instance builder, passing the LLVMDir and arguments.
//
CheckClangCompatibility();
const size_t argc = COpts.Remaining.size();
const char* const* argv = &COpts.Remaining[0];
std::vector<const char*> argvCompile;
if(argc && argv) {
argvCompile = std::vector<const char*>(argv, argv+1);
}
argvCompile.reserve(argc+5);
// Variables for storing the memory of the C-string arguments.
// FIXME: We shouldn't use C-strings in the first place, but just use
// std::string for clang arguments.
std::string overlayArg;
std::string cacheArg;
// If user has enabled C++ modules we add some special module flags to the
// compiler invocation.
if (COpts.CxxModules) {
// Enables modules in clang.
argvCompile.push_back("-fmodules");
argvCompile.push_back("-fcxx-modules");
// We want to use modules in local-submodule-visibility mode. This mode
// will probably be the future default mode for C++ modules in clang, so
// we want to start using right now.
// Maybe we have to remove this flag in the future when clang makes this
// mode the default and removes this internal flag.
argvCompile.push_back("-Xclang");
argvCompile.push_back("-fmodules-local-submodule-visibility");
// If we got a cache path, then we are supposed to place any modules
// we have to build in this directory.
if (!COpts.CachePath.empty()) {
cacheArg = std::string("-fmodules-cache-path=") + COpts.CachePath;
argvCompile.push_back(cacheArg.c_str());
}
// Disable the module hash. This gives us a flat file layout in the
// modules cache directory. In clang this is used to prevent modules from
// different compiler invocations to not collide, but we only have one
// compiler invocation in cling, so we don't need this.
argvCompile.push_back("-Xclang");
argvCompile.push_back("-fdisable-module-hash");
// Disable the warning when we import a module from extern C. Some headers
// from the STL are doing this and we can't really do anything about this.
argvCompile.push_back("-Wno-module-import-in-extern-c");
// Disable the warning when we import a module in a function body. This
// is a ROOT-specific issue tracked by ROOT-9088.
// FIXME: Remove after merging ROOT's PR1306.
argvCompile.push_back("-Wno-modules-import-nested-redundant");
// FIXME: We get an error "'cling/module.modulemap' from the precompiled
// header has been overridden". This comes from a bug that rootcling
// introduces by adding a lot of garbage in the PCH/PCM files because it
// essentially serializes its current state of the AST. That usually
// includes a few memory buffers which override their own contents.
// We know how to remove this: just implement a callback in clang
// which calls back the interpreter when a module file is built. This is
// a lot of work as it needs fixing rootcling. See RE-0003.
argvCompile.push_back("-Xclang");
argvCompile.push_back("-fno-validate-pch");
}
if (!COpts.Language) {
// We do C++ by default; append right after argv[0] if no "-x" given
argvCompile.push_back("-x");
argvCompile.push_back( "c++");
}
if (COpts.DefaultLanguage()) {
// By default, set the standard to what cling was compiled with.
// clang::driver::Compilation will do various things while initializing
// and by enforcing the std version now cling is telling clang what to
// do, rather than after clang has dedcuded a default.
switch (CxxStdCompiledWith()) {
case 17: argvCompile.emplace_back("-std=c++1z"); break;
case 14: argvCompile.emplace_back("-std=c++14"); break;
case 11: argvCompile.emplace_back("-std=c++11"); break;
default: llvm_unreachable("Unrecognized C++ version");
}
}
// This argument starts the cling instance with the x86 target. Otherwise,
// the first job in the joblist starts the cling instance with the nvptx
// target.
if(COpts.CUDA)
argvCompile.push_back("--cuda-host-only");
// argv[0] already inserted, get the rest
argvCompile.insert(argvCompile.end(), argv+1, argv + argc);
// Add host specific includes, -resource-dir if necessary, and -isysroot
std::string ClingBin;
if(argv) {
ClingBin = GetExecutablePath(argv[0]);
}
AddHostArguments(ClingBin, argvCompile, LLVMDir, COpts);
// Be explicit about the stdlib on OS X
// Would be nice on Linux but will warn 'argument unused during compilation'
// when -nostdinc++ is passed
#ifdef __APPLE__
if (!COpts.StdLib) {
#ifdef _LIBCPP_VERSION
argvCompile.push_back("-stdlib=libc++");
#elif defined(__GLIBCXX__)
argvCompile.push_back("-stdlib=libstdc++");
#endif
}
#endif
if (!COpts.HasOutput || !HasInput) {
argvCompile.push_back("-c");
argvCompile.push_back("-");
}
auto InvocationPtr = std::make_shared<clang::CompilerInvocation>();
// The compiler invocation is the owner of the diagnostic options.
// Everything else points to them.
DiagnosticOptions& DiagOpts = InvocationPtr->getDiagnosticOpts();
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
SetupDiagnostics(DiagOpts);
if (!Diags) {
cling::errs() << "Could not setup diagnostic engine.\n";
return nullptr;
}
llvm::Triple TheTriple(llvm::sys::getProcessTriple());
#ifdef LLVM_ON_WIN32
// COFF format currently needs a few changes in LLVM to function properly.
TheTriple.setObjectFormat(llvm::Triple::COFF);
#endif
clang::driver::Driver Drvr(ClingBin, TheTriple.getTriple(), *Diags);
//Drvr.setWarnMissingInput(false);
Drvr.setCheckInputsExist(false); // think foo.C(12)
llvm::ArrayRef<const char*>RF(&(argvCompile[0]), argvCompile.size());
std::unique_ptr<clang::driver::Compilation>
Compilation(Drvr.BuildCompilation(RF));
if (!Compilation) {
cling::errs() << "Couldn't create clang::driver::Compilation.\n";
return nullptr;
}
const driver::ArgStringList* CC1Args = GetCC1Arguments(Compilation.get());
if (!CC1Args) {
cling::errs() << "Could not get cc1 arguments.\n";
return nullptr;
}
clang::CompilerInvocation::CreateFromArgs(*InvocationPtr, CC1Args->data() + 1,
CC1Args->data() + CC1Args->size(),
*Diags);
// We appreciate the error message about an unknown flag (or do we? if not
// we should switch to a different DiagEngine for parsing the flags).
// But in general we'll happily go on.
Diags->Reset();
// Create and setup a compiler instance.
std::unique_ptr<CompilerInstance> CI(new CompilerInstance());
CI->setInvocation(InvocationPtr);
CI->setDiagnostics(Diags.get()); // Diags is ref-counted
if (!OnlyLex)
CI->getDiagnosticOpts().ShowColors = cling::utils::ColorizeOutput();
// Copied from CompilerInstance::createDiagnostics:
// Chain in -verify checker, if requested.
if (DiagOpts.VerifyDiagnostics)
Diags->setClient(new clang::VerifyDiagnosticConsumer(*Diags));
// Configure our handling of diagnostics.
ProcessWarningOptions(*Diags, DiagOpts);
if (COpts.HasOutput && !OnlyLex) {
ActionScan scan(clang::driver::Action::PrecompileJobClass,
clang::driver::Action::PreprocessJobClass);