From 4360733e1561bfeecee1ac76f5aa92979ab8c1e4 Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Thu, 26 Mar 2020 14:11:12 +0200 Subject: [PATCH 1/4] [cxxmodules] Teach cling to build modules; Build dependent modules explicitly. This allows external users to call rootcling as: rootcling bare-cling -xc++ -I${ROOTSYS}/etc -I ${headers_location} -fmodules -Xclang -emit-module -fmodule-name=tinyxml2 -fmodules-cache-path=${CMSSW_LIBDIR} -o ${module_file_location} ${headers_location}/module.modulemap --- cmake/modules/RootMacros.cmake | 58 +++++++ core/CMakeLists.txt | 38 +++++ core/clingutils/CMakeLists.txt | 15 +- core/dictgen/src/rootcling_impl.cxx | 63 +++---- core/metacling/src/TCling.cxx | 2 +- .../cling/include/cling/libc.modulemap | 1 + .../cling/lib/Interpreter/CIFactory.cpp | 154 ++++++++++++------ .../include/clang/Frontend/FrontendAction.h | 4 + .../clang/lib/Frontend/FrontendAction.cpp | 66 ++++---- 9 files changed, 280 insertions(+), 121 deletions(-) diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index 0888cabfd2f35..c3a6033b07eaa 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -254,6 +254,64 @@ function(ROOT_GET_INSTALL_DIR result) SET(${result} "${shared_lib_install_dir}" PARENT_SCOPE) endfunction(ROOT_GET_INSTALL_DIR) +#--------------------------------------------------------------------------------------------------- +#---ROOT_GENERATE_CXXMODULE( module_name DEPENDENCIES module_name1 module_name2 ) +# +function(ROOT_GENERATE_CXXMODULE module_name headers_location) + CMAKE_PARSE_ARGUMENTS(ARG "" "" "DEPENDENCIES" ${ARGN}) + + # rootcling bare-cling -I etc/ -x c++ -I /usr/include/c++/7/ -fmodules-cache-path=lib/ + # -fmodules -Xclang -emit-module -fmodule-name=std /usr/include/c++/7/module.modulemap + # -o std.pcm + set(root_libdir) + ROOT_GET_LIBRARY_OUTPUT_DIR(root_libdir) + + # Get all available modulemaps which ROOT will use. + get_property(root_modulemaps GLOBAL PROPERTY ROOT_MODULEMAPS) + + set(real_modulemap_file ${headers_location}/module.modulemap) + + if (NOT ${real_modulemap_file} IN_LIST root_modulemaps) + # The modulemap may be virtual (automatically mounted by rootcling) + set(virtual_modulemap_location "${CMAKE_BINARY_DIR}/etc/cling") + if (${module_name} MATCHES "Cling_Runtime") + # Cling_Runtime and Cling_Runtime_Extra are special we copy their + # module.modulemap.build as a module.modulemap in etc/cling. + set(virtual_modulemap_location "${virtual_modulemap_location}/module.modulemap") + else() + set(virtual_modulemap_location "${virtual_modulemap_location}/${module_name}.modulemap") + endif() + + if (${virtual_modulemap_location} IN_LIST root_modulemaps) + set(real_modulemap_file ${virtual_modulemap_location}) + elseif(NOT EXISTS ${real_modulemap_file}) + message(FATAL_ERROR "Neither '${headers_location}/module.modulemap' nor" + " '${real_modulemap_file}' exists for module '${module_name}'!") + endif() + endif() + + set(module_file_location ${root_libdir}/${module_name}.pcm) + set(dependencies ${real_modulemap_file}) + foreach(dep ${ARG_DEPENDENCIES}) + # Turn the target to a file.pcm. This allows us to add it as a file dependency + # in the DEPENDS clause of add_custom_command. This is the only way I found + # to trigger rebuild of the full chain of dependencies. + # Eg: a.pcm <- b.pcm <- c.pcm; rm a.pcm; ninja c.pcm; rebuilds a.pcm and b.pcm + list(APPEND dependencies ${root_libdir}/${dep}.pcm) + endforeach() + + add_custom_command(OUTPUT ${module_file_location} + COMMAND $ + bare-cling -xc++ -I${CMAKE_BINARY_DIR}/etc -I${headers_location} + -fmodules -Xclang -emit-module -fmodule-name=${module_name} + -fmodules-cache-path=${root_libdir} -o ${module_file_location} + ${headers_location}/module.modulemap + DEPENDS ${dependencies}) + + add_custom_target(${module_name} ALL DEPENDS ${module_file_location} ${dependencies}) + +endfunction(ROOT_GENERATE_CXXMODULE) + #--------------------------------------------------------------------------------------------------- #---ROOT_GENERATE_DICTIONARY( dictionary headerfiles NODEPHEADERS ghdr1 ghdr2 ... # MODULE module DEPENDENCIES dep1 dep2 diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 8a2b0df8e2ceb..72f789e38851c 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -155,6 +155,42 @@ add_subdirectory(rootcling_stage1) #------------------------------------------------------------------------------- ROOT_LINKER_LIBRARY(Core $ ${objectlibs} BUILTINS LZMA) +set(extra_cxxmodules_dependencies) +if(runtime_cxxmodules) + # We load the builtin modulemap at rootcling bare-cling init. + # FIXME: What happens when the /include/* changes? + #ROOT_GENERATE_CXXMODULE(_Builtin_stddef_max_align_t) + #ROOT_GENERATE_CXXMODULE(_Builtin_intrinsics) + set (libc) + if (APPLE) + set(libc Darwin) + else() + set(libc libc) + endif() + + ROOT_GENERATE_CXXMODULE(${libc} "/usr/include") + + get_property(cxx_headers_location GLOBAL PROPERTY ROOT_CLING_CXX_HEADERS_LOCATION) + + # Assume the first component is where the public headers are. + string(FIND ${cxx_headers_location} ":" idx) + string(SUBSTRING ${cxx_headers_location} 0 ${idx} cxx_headers_location) + + ROOT_GENERATE_CXXMODULE(std ${cxx_headers_location} DEPENDENCIES ${libc}) + ROOT_GENERATE_CXXMODULE(Cling_Runtime ${CMAKE_BINARY_DIR}/etc/cling DEPENDENCIES std) + ROOT_GENERATE_CXXMODULE(Cling_Runtime_Extra ${CMAKE_BINARY_DIR}/etc/cling DEPENDENCIES Cling_Runtime) + + if(cuda) + ROOT_GENERATE_CXXMODULE(cuda ${CUDA_INCLUDE_DIRS}) + endif(cuda) + + ROOT_GENERATE_CXXMODULE(ROOT_Config ${CMAKE_BINARY_DIR}/include DEPENDENCIES Cling_Runtime_Extra) + ROOT_GENERATE_CXXMODULE(ROOT_Rtypes ${CMAKE_BINARY_DIR}/include DEPENDENCIES ROOT_Config) + ROOT_GENERATE_CXXMODULE(ROOT_Foundation_C ${CMAKE_BINARY_DIR}/include DEPENDENCIES ROOT_Rtypes) + ROOT_GENERATE_CXXMODULE(ROOT_Foundation_Stage1_NoRTTI ${CMAKE_BINARY_DIR}/include DEPENDENCIES ROOT_Foundation_C) + + set(extra_cxxmodules_dependencies ${libc} std Cling_Runtime Cling_Runtime_Extra ROOT_Config ROOT_Rtypes ROOT_Foundation_Stage1_NoRTTI) +endif(runtime_cxxmodules) if (libcxx AND NOT APPLE) # In case we use libcxx and glibc together there is a mismatch of the @@ -217,6 +253,8 @@ ROOT_GENERATE_DICTIONARY(G__Core -writeEmptyRootPCM LINKDEF base/inc/LinkDef.h + DEPENDENCIES + ${extra_cxxmodules_dependencies} ) target_include_directories(G__Core PRIVATE ${CMAKE_SOURCE_DIR}/core/clingutils/inc) diff --git a/core/clingutils/CMakeLists.txt b/core/clingutils/CMakeLists.txt index dada0723b7a03..0798909757298 100644 --- a/core/clingutils/CMakeLists.txt +++ b/core/clingutils/CMakeLists.txt @@ -125,6 +125,8 @@ if (runtime_cxxmodules) endif() endif(runtime_cxxmodules) +set(root_etc_cling_modulemaps) + foreach(file ${custom_modulemaps} Interpreter/DynamicExprInfo.h Interpreter/DynamicLookupRuntimeUniverse.h @@ -137,7 +139,10 @@ foreach(file ${custom_modulemaps} set(dest_file ${file}) if (${file} STREQUAL "module.modulemap.build") set(dest_file "module.modulemap") - elseif(NOT ${file} MATCHES ".*modulemap") + endif() + if(${file} MATCHES ".*modulemap") + list(APPEND root_etc_cling_modulemaps ${CMAKE_BINARY_DIR}/etc/cling/${dest_file}) + else() # We do not want our modulemap to be considered part of the PCH. set_property(GLOBAL APPEND PROPERTY CLINGETCPCH etc/cling/${dest_file}) endif() @@ -165,6 +170,7 @@ foreach(file wchar.h bits/stat.h bits/time.h) endforeach() set(stamp_file ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/LLVMRES.stamp) +get_property(root_modulemaps GLOBAL PROPERTY ROOT_MODULEMAPS) if(MSVC) add_custom_command(OUTPUT ${stamp_file} COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/etc/cling/lib/clang/${CLANG_RESOURCE_DIR_VERSION}/include @@ -174,6 +180,7 @@ if(MSVC) ${CMAKE_BINARY_DIR}/etc/cling/lib/clang/${CLANG_RESOURCE_DIR_VERSION}/include COMMAND ${CMAKE_COMMAND} -E touch ${stamp_file} DEPENDS ${files_to_copy} + BYPRODUCTS ${root_etc_cling_modulemaps} COMMENT "Copying LLVM resource and header files") else() add_custom_command(OUTPUT ${stamp_file} @@ -193,8 +200,14 @@ else() ${copy_commands} COMMAND ${CMAKE_COMMAND} -E touch ${stamp_file} DEPENDS ${files_to_copy} + BYPRODUCTS ${root_etc_cling_modulemaps} COMMENT "Copying LLVM resource and header files") endif() + +# Register the main modulemap file. +list(APPEND root_etc_cling_modulemaps ${CMAKE_BINARY_DIR}/include/module.modulemap) +set_property(GLOBAL APPEND PROPERTY ROOT_MODULEMAPS ${root_etc_cling_modulemaps}) + add_custom_target(LLVMRES DEPENDS ${stamp_file} CLING) # CLING is a shorthand for CLING_LIBRARIES and some other clang-specific # dependencies which ensure the correct order of building. Then the cling header diff --git a/core/dictgen/src/rootcling_impl.cxx b/core/dictgen/src/rootcling_impl.cxx index 5a000dfde59e4..75e1d245427f1 100644 --- a/core/dictgen/src/rootcling_impl.cxx +++ b/core/dictgen/src/rootcling_impl.cxx @@ -3938,7 +3938,9 @@ static llvm::StringRef GetModuleNameFromRdictName(llvm::StringRef rdictName) { // Try to get the module name in the modulemap based on the filepath. llvm::StringRef moduleName = llvm::sys::path::filename(rdictName); - moduleName.consume_front("lib"); + // FIXME: Rename the libc module and delete this special case. + if (!rdictName.startswith("libc")) + moduleName.consume_front("lib"); moduleName.consume_back(".pcm"); moduleName.consume_back("_rdict"); return moduleName; @@ -3992,23 +3994,37 @@ int RootClingMain(int argc, llvm::cl::ParseCommandLineOptions(argc, argv, "rootcling"); - std::string llvmResourceDir = std::string(gDriverConfig->fTROOT__GetEtcDir()) + "/cling"; + llvm::SmallString<512> llvmDir(gDriverConfig->fTROOT__GetEtcDir()); + llvm::sys::path::append(llvmDir, "cling"); + llvm::SmallString<512> resourcePathInc(llvmDir); + llvm::sys::path::append(resourcePathInc, "lib", "clang", "5.0.0"); + assert(llvm::sys::fs::exists(resourcePathInc)); + std::string llvmResourceDir = resourcePathInc.str().str(); if (gBareClingSubcommand) { std::vector clingArgsC; clingArgsC.push_back(executableFileName); // Help cling finds its runtime (RuntimeUniverse.h and such). + //clingArgsC.push_back("-I"); + //clingArgsC.push_back(gDriverConfig->fTROOT__GetEtcDir()); + + llvm::sys::path::append(resourcePathInc, "include"); clingArgsC.push_back("-I"); - clingArgsC.push_back(gDriverConfig->fTROOT__GetEtcDir()); + clingArgsC.push_back(resourcePathInc.c_str()); + // Add the builtin modulemap for clang. See -fbuiltin-module-map + llvm::SmallString<512> builtinModuleMap("-fmodule-map-file="); + builtinModuleMap.append(resourcePathInc); + llvm::sys::path::append(builtinModuleMap, "module.modulemap"); + clingArgsC.push_back(resourcePathInc.c_str()); - //clingArgsC.push_back("-resource-dir"); - //clingArgsC.push_back(llvmResourceDir.c_str()); + clingArgsC.push_back("-nobuiltininc"); + clingArgsC.push_back("-noruntime"); for (const std::string& Opt : gOptBareClingSink) clingArgsC.push_back(Opt.c_str()); auto interp = llvm::make_unique(clingArgsC.size(), &clingArgsC[0], - llvmResourceDir.c_str()); + llvmDir.c_str()); // FIXME: Diagnose when we have misspelled a flag. Currently we show no // diagnostic and report exit as success. return interp->getDiagnostics().hasFatalErrorOccurred(); @@ -4218,40 +4234,11 @@ int RootClingMain(int argc, // Specify the module name that we can lookup the module in the modulemap. outputFile = llvm::sys::path::stem(gOptSharedLibFileName).str(); - // Try to get the module name in the modulemap based on the filepath. moduleName = GetModuleNameFromRdictName(outputFile); - clingArgsInterpreter.push_back("-fmodule-name"); clingArgsInterpreter.push_back(moduleName.str()); std::string moduleCachePath = llvm::sys::path::parent_path(gOptSharedLibFileName).str(); - // FIXME: This is a horrible workaround to fix the incremental builds. - // The enumerated modules are built by clang impicitly based on #include of - // a header which is contained within that module. The build system has - // no way to track dependencies on them and trigger a rebuild. - // A possible solution can be to disable completely the implicit build of - // modules and each module to be built by rootcling. We need to teach - // rootcling how to build modules with no IO support. - if (moduleName == "Core") { - assert(gDriverConfig->fBuildingROOTStage1); - remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_intrinsics.pcm").str().c_str()); - remove((moduleCachePath + llvm::sys::path::get_separator() + "_Builtin_stddef_max_align_t.pcm").str().c_str()); - remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime.pcm").str().c_str()); - remove((moduleCachePath + llvm::sys::path::get_separator() + "Cling_Runtime_Extra.pcm").str().c_str()); -#ifdef R__MACOSX - remove((moduleCachePath + llvm::sys::path::get_separator() + "Darwin.pcm").str().c_str()); -#else - remove((moduleCachePath + llvm::sys::path::get_separator() + "libc.pcm").str().c_str()); -#endif - remove((moduleCachePath + llvm::sys::path::get_separator() + "std.pcm").str().c_str()); - remove((moduleCachePath + llvm::sys::path::get_separator() + "cuda.pcm").str().c_str()); - remove((moduleCachePath + llvm::sys::path::get_separator() + "boost.pcm").str().c_str()); - remove((moduleCachePath + llvm::sys::path::get_separator() + "tinyxml2.pcm").str().c_str()); - remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Config.pcm").str().c_str()); - remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Rtypes.pcm").str().c_str()); - remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_C.pcm").str().c_str()); - remove((moduleCachePath + llvm::sys::path::get_separator() + "ROOT_Foundation_Stage1_NoRTTI.pcm").str().c_str()); - } // Set the C++ modules output directory to the directory where we generate // the shared library. @@ -4296,7 +4283,7 @@ int RootClingMain(int argc, #endif owningInterpPtr.reset(new cling::Interpreter(clingArgsC.size(), &clingArgsC[0], - llvmResourceDir.c_str())); + llvmDir.c_str())); interpPtr = owningInterpPtr.get(); // Force generation of _Builtin_intrinsics by rootcling_stage1. // The rest of the modules are implicitly generated by cling when including @@ -4358,7 +4345,7 @@ int RootClingMain(int argc, if (gOptCxxModule) { for (llvm::StringRef DepMod : gOptModuleDependencies) { if (DepMod.endswith("_rdict.pcm")) { - ROOT::TMetaUtils::Warning(0, "'%s' value is deprecated. Please use []%s.pcm\n", + ROOT::TMetaUtils::Warning(0, "'%s' value is deprecated. Please use []%s.pcm\n", DepMod.data(), GetModuleNameFromRdictName(DepMod).str().data()); } @@ -4693,7 +4680,7 @@ int RootClingMain(int argc, clingArgs.push_back("-Ietc/cling/cint"); // For multiset and multimap if (!ldefr.Parse(selectionRules, interpPragmaSource, clingArgs, - llvmResourceDir.c_str())) { + llvmDir.c_str())) { ROOT::TMetaUtils::Error(0, "Parsing Linkdef file %s\n", linkdefFilename.c_str()); rootclingRetCode += 1; } else { diff --git a/core/metacling/src/TCling.cxx b/core/metacling/src/TCling.cxx index a8bcca6811b9f..8062fb2dc504d 100644 --- a/core/metacling/src/TCling.cxx +++ b/core/metacling/src/TCling.cxx @@ -1455,7 +1455,7 @@ TCling::TCling(const char *name, const char *title, const char* const argv[]) extraArgs && *extraArgs; ++extraArgs) { if (!strcmp(*extraArgs, "-resource-dir")) { // Take the next arg as the llvm resource directory. - llvmResourceDir = *(++extraArgs); + //llvmResourceDir = *(++extraArgs); } else { interpArgs.push_back(*extraArgs); } diff --git a/interpreter/cling/include/cling/libc.modulemap b/interpreter/cling/include/cling/libc.modulemap index 87654b1ecf1fe..f6c87a0da7cbc 100644 --- a/interpreter/cling/include/cling/libc.modulemap +++ b/interpreter/cling/include/cling/libc.modulemap @@ -43,6 +43,7 @@ module "libc" [system] [extern_c] [no_undeclared_includes] { header "signal.h" } module "stddef.h" { + requires !header_existence export * textual header "stddef.h" } diff --git a/interpreter/cling/lib/Interpreter/CIFactory.cpp b/interpreter/cling/lib/Interpreter/CIFactory.cpp index 50a7497fa0919..2f0bc5dec58c5 100644 --- a/interpreter/cling/lib/Interpreter/CIFactory.cpp +++ b/interpreter/cling/lib/Interpreter/CIFactory.cpp @@ -22,6 +22,7 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Job.h" +#include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/FrontendDiagnostic.h" @@ -31,6 +32,7 @@ #include "clang/Frontend/VerifyDiagnosticConsumer.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorOptions.h" +#include "clang/Parse/ParseAST.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Serialization/ASTReader.h" @@ -343,7 +345,7 @@ namespace { #endif // _MSC_VER - if (!opts.ResourceDir && !opts.NoBuiltinInc) { + if (!opts.ResourceDir) { std::string resourcePath = getResourceDir(llvmdir); // FIXME: Handle cases, where the cling is part of a library/framework. @@ -646,15 +648,19 @@ namespace { std::string MOverlay; #ifdef LLVM_ON_WIN32 - maybeAppendOverlayEntry(cIncLoc.str(), "libc_msvc.modulemap", - clingIncLoc.str(), MOverlay); - maybeAppendOverlayEntry(stdIncLoc.str(), "std_msvc.modulemap", - clingIncLoc.str(), MOverlay); + if (!cIncLoc.empty()) + maybeAppendOverlayEntry(cIncLoc.str(), "libc_msvc.modulemap", + clingIncLoc.str(), MOverlay); + if (!stdIncLoc.empty()) + maybeAppendOverlayEntry(stdIncLoc.str(), "std_msvc.modulemap", + clingIncLoc.str(), MOverlay); #else - maybeAppendOverlayEntry(cIncLoc.str(), "libc.modulemap", clingIncLoc.str(), - MOverlay); - maybeAppendOverlayEntry(stdIncLoc.str(), "std.modulemap", clingIncLoc.str(), - MOverlay); + if (!cIncLoc.empty()) + maybeAppendOverlayEntry(cIncLoc.str(), "libc.modulemap", clingIncLoc.str(), + MOverlay); + if (!stdIncLoc.empty()) + maybeAppendOverlayEntry(stdIncLoc.str(), "std.modulemap", clingIncLoc.str(), + MOverlay); #endif // LLVM_ON_WIN32 if (!tinyxml2IncLoc.empty()) @@ -1152,6 +1158,18 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts, /*FindModuleFileExtensions=*/true, Listener, HSOpts.ModulesValidateDiagnosticOptions); + } else if (FrontendOpts.ProgramAction == clang::frontend::GenerateModule) { + // We will not call ParseAST which intializes the Sema via the Parser. + //CI.getSema().Initialize(); + FrontendInputFile Input = FrontendOpts.Inputs[0]; + /// Overwrite the virtual main source file with the modulemap. + CI.InitializeSourceManager(Input); + + clang::SetupModuleBuiltFromModuleMap(CI, Input); + + clang::ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats, + + CI.getFrontendOpts().SkipFunctionBodies); } } @@ -1338,7 +1356,11 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts, // Configure our handling of diagnostics. ProcessWarningOptions(*Diags, DiagOpts); - if (COpts.HasOutput && !OnlyLex) { + clang::CompilerInvocation& Invocation = CI->getInvocation(); + FrontendOptions& FrontendOpts = Invocation.getFrontendOpts(); + + if (COpts.HasOutput && !OnlyLex && + FrontendOpts.ProgramAction != clang::frontend::GenerateModule) { ActionScan scan(clang::driver::Action::PrecompileJobClass, clang::driver::Action::PreprocessJobClass); if (!scan.find(Compilation.get())) { @@ -1354,7 +1376,6 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts, } CI->createFileManager(); - clang::CompilerInvocation& Invocation = CI->getInvocation(); std::string& PCHFile = Invocation.getPreprocessorOpts().ImplicitPCHInclude; bool InitLang = true, InitTarget = true; if (!PCHFile.empty()) { @@ -1422,8 +1443,6 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts, } } - FrontendOptions& FrontendOpts = Invocation.getFrontendOpts(); - // Register the externally constructed extensions. assert(FrontendOpts.ModuleFileExtensions.empty() && "Extensions exist!"); for (auto& E : moduleExtensions) @@ -1458,22 +1477,23 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts, // be registered as $PWD instead, which is stable even after chdirs. FM.getDirectory(platform::GetCwd()); - // Build the virtual file, Give it a name that's likely not to ever - // be #included (so we won't get a clash in clang's cache). - const char* Filename = "<<< cling interactive line includer >>>"; - const FileEntry* FE = FM.getVirtualFile(Filename, 1U << 15U, time(0)); - - // Tell ASTReader to create a FileID even if this file does not exist: - SM->setFileIsTransient(FE); - FileID MainFileID = SM->createFileID(FE, SourceLocation(), SrcMgr::C_User); - SM->setMainFileID(MainFileID); - const SrcMgr::SLocEntry& MainFileSLocE = SM->getSLocEntry(MainFileID); - const SrcMgr::ContentCache* MainFileCC - = MainFileSLocE.getFile().getContentCache(); - if (!Buffer) - Buffer = llvm::MemoryBuffer::getMemBuffer("/*CLING DEFAULT MEMBUF*/;\n"); - const_cast(MainFileCC)->setBuffer(std::move(Buffer)); - + if (COpts.ModuleName.empty() || !COpts.HasOutput) { + // Build the virtual file, Give it a name that's likely not to ever + // be #included (so we won't get a clash in clang's cache). + const char* Filename = "<<< cling interactive line includer >>>"; + const FileEntry* FE = FM.getVirtualFile(Filename, 1U << 15U, time(0)); + + // Tell ASTReader to create a FileID even if this file does not exist: + SM->setFileIsTransient(FE); + FileID MainFileID = SM->createFileID(FE, SourceLocation(), SrcMgr::C_User); + SM->setMainFileID(MainFileID); + const SrcMgr::SLocEntry& MainFileSLocE = SM->getSLocEntry(MainFileID); + const SrcMgr::ContentCache* MainFileCC + = MainFileSLocE.getFile().getContentCache(); + if (!Buffer) + Buffer = llvm::MemoryBuffer::getMemBuffer("/*CLING DEFAULT MEMBUF*/;\n"); + const_cast(MainFileCC)->setBuffer(std::move(Buffer)); + } // Create TargetInfo for the other side of CUDA and OpenMP compilation. if ((CI->getLangOpts().CUDA || CI->getLangOpts().OpenMPIsDevice) && !CI->getFrontendOpts().AuxTriple.empty()) { @@ -1484,7 +1504,7 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts, } // Set up the preprocessor - CI->createPreprocessor(TU_Complete); + CI->createPreprocessor(COpts.ModuleName.empty() ? TU_Complete : TU_Module); // With modules, we now start adding prebuilt module paths to the CI. // Modules from those paths are treated like they are never out of date @@ -1515,43 +1535,73 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts, // generation of the PCM file itself in case we want to generate // a C++ module with the current interpreter instance. if (COpts.CxxModules && !COpts.ModuleName.empty()) { - // Code below from the (private) code in the GenerateModuleAction class. - llvm::SmallVector Output; - llvm::sys::path::append(Output, COpts.CachePath, - COpts.ModuleName + ".pcm"); - StringRef ModuleOutputFile = StringRef(Output.data(), Output.size()); + llvm::StringRef InFile = FrontendOpts.Inputs[0].getFile(); + + if (COpts.HasOutput) { + Consumers.pop_back(); + /// The driver sets the location of the module file in /tmp/... + FrontendOpts.OutputFile + = Compilation->getInputArgs().getLastArg(driver::options::OPT_o)->getValue(); + // The driver tries to append a non-existent resource dir if none was + // specified. + if (COpts.ResourceDir) + CI->getHeaderSearchOpts().ResourceDir = ""; + } else { + //GenerateModuleFromModuleMapAction::CreateOutputFile: + // If no output file was provided, figure out where this module would go + // in the module cache. + //if (FrontendOpts.OutputFile.empty()) { + StringRef ModuleMapFile = FrontendOpts.OriginalModuleMap; + if (ModuleMapFile.empty()) + ModuleMapFile = InFile; + + HeaderSearch &HS = PP.getHeaderSearchInfo(); + FrontendOpts.OutputFile = + HS.getModuleFileName(CI->getLangOpts().CurrentModule, ModuleMapFile, + /*UsePrebuiltPath=*/false); + //} + } + // We use createOutputFile here because this is exposed via libclang, and we + // must disable the RemoveFileOnSignal behavior. + // We use a temporary to avoid race conditions. std::unique_ptr OS = - CI->createOutputFile(ModuleOutputFile, /*Binary=*/true, - /*RemoveFileOnSignal=*/false, "", - /*Extension=*/"", /*useTemporary=*/true, - /*CreateMissingDirectories=*/true); + CI->createOutputFile(FrontendOpts.OutputFile, /*Binary=*/true, + /*RemoveFileOnSignal=*/false, InFile, + /*Extension=*/"", /*useTemporary=*/true, + /*CreateMissingDirectories=*/true); + + // GenerateModuleAction::CreateASTConsumer assert(OS); std::string Sysroot; + std::string OutputFile = FrontendOpts.OutputFile; auto Buffer = std::make_shared(); Consumers.push_back(llvm::make_unique( - CI->getPreprocessor(), ModuleOutputFile, Sysroot, Buffer, + CI->getPreprocessor(), OutputFile, Sysroot, Buffer, CI->getFrontendOpts().ModuleFileExtensions, /*AllowASTWithErrors=*/false, /*IncludeTimestamps=*/ +CI->getFrontendOpts().BuildingImplicitModule)); + Consumers.push_back( CI->getPCHContainerWriter().CreatePCHContainerGenerator( - *CI, "", ModuleOutputFile, std::move(OS), Buffer)); - - // Set the current module name for clang. With that clang doesn't start - // to build the current module on demand when we include a header - // from the current module. - CI->getLangOpts().CurrentModule = COpts.ModuleName; - CI->getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap); - - // Push the current module to the build stack so that clang knows when - // we have a cyclic dependency. - SM->pushModuleBuildStack(COpts.ModuleName, - FullSourceLoc(SourceLocation(), *SM)); + *CI, InFile, OutputFile, std::move(OS), Buffer)); + + if (FrontendOpts.ProgramAction != clang::frontend::GenerateModule) { + // Set the current module name for clang. With that clang doesn't start + // to build the current module on demand when we include a header + // from the current module. + CI->getLangOpts().CurrentModule = COpts.ModuleName; + CI->getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap); + + // Push the current module to the build stack so that clang knows when + // we have a cyclic dependency. + SM->pushModuleBuildStack(COpts.ModuleName, + FullSourceLoc(SourceLocation(), *SM)); + } } std::unique_ptr multiConsumer( diff --git a/interpreter/llvm/src/tools/clang/include/clang/Frontend/FrontendAction.h b/interpreter/llvm/src/tools/clang/include/clang/Frontend/FrontendAction.h index 7ae6173512a68..3d6c3eba6fde9 100644 --- a/interpreter/llvm/src/tools/clang/include/clang/Frontend/FrontendAction.h +++ b/interpreter/llvm/src/tools/clang/include/clang/Frontend/FrontendAction.h @@ -29,6 +29,10 @@ #include namespace clang { + +bool SetupModuleBuiltFromModuleMap(CompilerInstance &CI, + FrontendInputFile& Input); + class ASTMergeAction; class CompilerInstance; diff --git a/interpreter/llvm/src/tools/clang/lib/Frontend/FrontendAction.cpp b/interpreter/llvm/src/tools/clang/lib/Frontend/FrontendAction.cpp index 2fd88652bb88a..a8cca92b1a663 100644 --- a/interpreter/llvm/src/tools/clang/lib/Frontend/FrontendAction.cpp +++ b/interpreter/llvm/src/tools/clang/lib/Frontend/FrontendAction.cpp @@ -509,6 +509,42 @@ getInputBufferForModule(CompilerInstance &CI, Module *M) { HeaderContents, Module::getModuleInputBufferName()); } +///\returns true on success. +bool clang::SetupModuleBuiltFromModuleMap(CompilerInstance &CI, + FrontendInputFile& Input) { + CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap); + + std::string PresumedModuleMapFile; + unsigned OffsetToContents; + if (loadModuleMapForModuleBuild(CI, Input.isSystem(), + Input.isPreprocessed(), + PresumedModuleMapFile, OffsetToContents)) + return false; + + auto *CurrentModule = prepareToBuildModule(CI, Input.getFile()); + if (!CurrentModule) + return false; + + CurrentModule->PresumedModuleMapFile = PresumedModuleMapFile; + + if (OffsetToContents) + // If the module contents are in the same file, skip to them. + CI.getPreprocessor().setSkipMainFilePreamble(OffsetToContents, true); + else { + // Otherwise, convert the module description to a suitable input buffer. + auto Buffer = getInputBufferForModule(CI, CurrentModule); + if (!Buffer) + return false; + + // Reinitialize the main file entry to refer to the new input. + if (!CI.InitializeSourceManager(FrontendInputFile( + Buffer.release(), Input.getKind().withFormat(InputKind::Source), + CurrentModule->IsSystem))) + return false; + } + return true; +} + bool FrontendAction::BeginSourceFile(CompilerInstance &CI, const FrontendInputFile &RealInput) { FrontendInputFile Input(RealInput); @@ -723,36 +759,8 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // For module map files, we first parse the module map and synthesize a // "" buffer before more conventional processing. if (Input.getKind().getFormat() == InputKind::ModuleMap) { - CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleMap); - - std::string PresumedModuleMapFile; - unsigned OffsetToContents; - if (loadModuleMapForModuleBuild(CI, Input.isSystem(), - Input.isPreprocessed(), - PresumedModuleMapFile, OffsetToContents)) - goto failure; - - auto *CurrentModule = prepareToBuildModule(CI, Input.getFile()); - if (!CurrentModule) + if (!SetupModuleBuiltFromModuleMap(CI, Input)) goto failure; - - CurrentModule->PresumedModuleMapFile = PresumedModuleMapFile; - - if (OffsetToContents) - // If the module contents are in the same file, skip to them. - CI.getPreprocessor().setSkipMainFilePreamble(OffsetToContents, true); - else { - // Otherwise, convert the module description to a suitable input buffer. - auto Buffer = getInputBufferForModule(CI, CurrentModule); - if (!Buffer) - goto failure; - - // Reinitialize the main file entry to refer to the new input. - if (!CI.InitializeSourceManager(FrontendInputFile( - Buffer.release(), Input.getKind().withFormat(InputKind::Source), - CurrentModule->IsSystem))) - goto failure; - } } // Initialize the action. From c20406ba2bd4ad4455ff35b81ff2371ee3558e8c Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Fri, 8 May 2020 07:11:43 +0000 Subject: [PATCH 2/4] [cling] Move C++ header location detection in a separate function. This will allow us to generalize it to resolve C headers as well. --- .../cling/lib/Interpreter/CMakeLists.txt | 238 +++++++++--------- 1 file changed, 123 insertions(+), 115 deletions(-) diff --git a/interpreter/cling/lib/Interpreter/CMakeLists.txt b/interpreter/cling/lib/Interpreter/CMakeLists.txt index c68ca4d3ed671..c07fe413cdcb6 100644 --- a/interpreter/cling/lib/Interpreter/CMakeLists.txt +++ b/interpreter/cling/lib/Interpreter/CMakeLists.txt @@ -107,140 +107,148 @@ add_cling_library(clingInterpreter OBJECT ${LIBS} ) +function(stripNewLine strVal varName) + string(STRIP "${strVal}" strVal) + string(REGEX REPLACE "\\n$" "" strVal "${strVal}") + SET(${varName} ${strVal} PARENT_SCOPE) +endfunction() + +function(detect_header_location out_header_path out_compiler_binary) + if (NOT UNIX) + message(FATAL_ERROR "Currently works only for unix!") + endif() -if (UNIX) - set_source_files_properties(Exception.cpp COMPILE_FLAGS "-fexceptions -frtti") - set_source_files_properties(Interpreter.cpp COMPILE_FLAGS "-fexceptions") - - # Remove all -I from CMAKE_CXX_FLAGS - string(REPLACE ";" " " __flags "${CMAKE_CXX_FLAGS}") - string(REGEX REPLACE "-I[^ ]+" "" CLING_COMPILER_FLAGS_NO_I "${__flags}") - - option(CLING_CXX_PATH "Compiler cling will invoke for c++ headers." "") - option(CLING_CXX_HEADERS "Path cling will use for c++ headers." "") - - function(stripNewLine strVal varName) - string(STRIP "${strVal}" strVal) - string(REGEX REPLACE "\\n$" "" strVal "${strVal}") - SET(${varName} ${strVal} PARENT_SCOPE) - endfunction() - - if(NOT CLING_CXX_PATH) - # Remove absolute path from CMAKE_CXX_COMPILER - get_filename_component(_name ${CMAKE_CXX_COMPILER} NAME) - get_filename_component(_path ${CMAKE_CXX_COMPILER} PATH) - - # This should probably be more general...but how? - if(_name STREQUAL "ccache" OR _name STREQUAL "distcc") - separate_arguments(_arg_list UNIX_COMMAND "${CMAKE_CXX_COMPILER_ARG1}") - if (_arg_list) - list(GET _arg_list 0 _name) - string(STRIP "${_name}" _name) - if (APPLE) - execute_process(COMMAND xcrun -f ${_name} - OUTPUT_VARIABLE CLING_CXX_FOUND - OUTPUT_STRIP_TRAILING_WHITESPACE) - stripNewLine("${CLING_CXX_FOUND}" CLING_CXX_FOUND) - else() - find_program(_cling_cxx_path "${_name}") - execute_process(COMMAND ${_cling_cxx_path} -xc++ -E -v /dev/null - OUTPUT_QUIET ERROR_VARIABLE _cling_cxx_path) - - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - execute_process( - COMMAND echo ${_cling_cxx_path} - COMMAND grep "COLLECT_GCC=" - OUTPUT_VARIABLE _cling_cxx_path) - string(REPLACE "COLLECT_GCC=" "" _cling_cxx_path "${_cling_cxx_path}") - - elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - execute_process( - COMMAND echo ${_cling_cxx_path} - COMMAND grep "/${_name}.*\" -cc1" - OUTPUT_VARIABLE _cling_clng_path) - - if(NOT _cling_clng_path) - execute_process( - COMMAND echo ${_cling_cxx_path} - COMMAND grep "/clang.*\" -cc1" - OUTPUT_VARIABLE _cling_clng_path) - endif() - - separate_arguments(_arg_list UNIX_COMMAND "${_cling_clng_path}") - if (_arg_list) - list(GET _arg_list 0 _cling_cxx_path) - endif() + # Remove absolute path from CMAKE_CXX_COMPILER + get_filename_component(_name ${CMAKE_CXX_COMPILER} NAME) + get_filename_component(_path ${CMAKE_CXX_COMPILER} PATH) + + # This should probably be more general...but how? + if(_name STREQUAL "ccache" OR _name STREQUAL "distcc") + separate_arguments(_arg_list UNIX_COMMAND "${CMAKE_CXX_COMPILER_ARG1}") + if (_arg_list) + list(GET _arg_list 0 _name) + string(STRIP "${_name}" _name) + if (APPLE) + execute_process(COMMAND xcrun -f ${_name} + OUTPUT_VARIABLE CLING_CXX_FOUND + OUTPUT_STRIP_TRAILING_WHITESPACE) + stripNewLine("${CLING_CXX_FOUND}" CLING_CXX_FOUND) + else() + find_program(_cling_cxx_path "${_name}") + execute_process(COMMAND ${_cling_cxx_path} -xc++ -E -v /dev/null + OUTPUT_QUIET ERROR_VARIABLE _cling_cxx_path) + + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + execute_process(COMMAND echo ${_cling_cxx_path} + COMMAND grep "COLLECT_GCC=" + OUTPUT_VARIABLE _cling_cxx_path) + + string(REPLACE "COLLECT_GCC=" "" _cling_cxx_path "${_cling_cxx_path}") + + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + execute_process(COMMAND echo ${_cling_cxx_path} + COMMAND grep "/${_name}.*\" -cc1" + OUTPUT_VARIABLE _cling_clng_path) + + if(NOT _cling_clng_path) + execute_process(COMMAND echo ${_cling_cxx_path} + COMMAND grep "/clang.*\" -cc1" + OUTPUT_VARIABLE _cling_clng_path) endif() - stripNewLine("${_cling_cxx_path}" _cling_cxx_path) - set(CLING_CXX_FOUND "${_cling_cxx_path}") + separate_arguments(_arg_list UNIX_COMMAND "${_cling_clng_path}") + if (_arg_list) + list(GET _arg_list 0 _cling_cxx_path) + endif() endif() - if (NOT EXISTS "${CLING_CXX_FOUND}") - find_program(CLING_CXX_FOUND "${_name}") - endif() - else() - set(CLING_CXX_FOUND "") - set(_name "") + stripNewLine("${_cling_cxx_path}" _cling_cxx_path) + set(CLING_CXX_FOUND "${_cling_cxx_path}") endif() - if (EXISTS ${CLING_CXX_FOUND}) - set(CLING_CXX_PATH ${CLING_CXX_FOUND}) - get_filename_component(_name ${CLING_CXX_PATH} NAME) - get_filename_component(_path ${CLING_CXX_PATH} PATH) - else() - set(CLING_CXX_PATH "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}") - if(_name) - set(CLING_CXX_RLTV "${_name}") - endif() - set(_path "__THISREALLYBETTERNOTBEINPATH_THANKS__") + if (NOT EXISTS "${CLING_CXX_FOUND}") + find_program(CLING_CXX_FOUND "${_name}") endif() else() - # FIXME: In some ccache setups we can have a soft link pointing to ccache - # binary. Eg. /usr/local/gcc -> /usr/bin/ccache. Resolving the realpath - # we will get to the ccache and not the intended compiler binary. This - # could be fixed if we run 'gcc -###' which will give us the correct info. - get_filename_component(_realpath ${CMAKE_CXX_COMPILER} REALPATH) - get_filename_component(_name ${_realpath} NAME) - get_filename_component(_path ${_realpath} PATH) + set(CLING_CXX_FOUND "") + set(_name "") endif() - # Test if path compiler is on PATH. - string(REPLACE ":" ";" _pathlist $ENV{PATH}) - foreach (_pathcomp ${_pathlist}) - get_filename_component(_pathcomp ${_pathcomp} REALPATH) - if (_path STREQUAL _pathcomp) - # This adds a lot of unneccessary flags, but may be useful if there's - # a flag that should be passed to cling. - set(CLING_CXX_RLTV ${_name}) - break() + if (EXISTS ${CLING_CXX_FOUND}) + set(CLING_CXX_PATH ${CLING_CXX_FOUND}) + get_filename_component(_name ${CLING_CXX_PATH} NAME) + get_filename_component(_path ${CLING_CXX_PATH} PATH) + else() + set(CLING_CXX_PATH "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}") + if(_name) + set(CLING_CXX_RLTV "${_name}") endif() - endforeach() + set(_path "__THISREALLYBETTERNOTBEINPATH_THANKS__") + endif() + else() + # FIXME: In some ccache setups we can have a soft link pointing to ccache + # binary. Eg. /usr/local/gcc -> /usr/bin/ccache. Resolving the realpath + # we will get to the ccache and not the intended compiler binary. This + # could be fixed if we run 'gcc -###' which will give us the correct info. + get_filename_component(_realpath ${CMAKE_CXX_COMPILER} REALPATH) + get_filename_component(_name ${_realpath} NAME) + get_filename_component(_path ${_realpath} PATH) + endif() - # FIXME: Perhaps CLING_CXX_RLTV should have a better name? - if(NOT CLING_CXX_RLTV AND NOT CLING_CXX_PATH) - # We got nothing, just use whatever CMake is using. - set(CLING_CXX_PATH ${CMAKE_CXX_COMPILER}) + # Test if path compiler is on PATH. + string(REPLACE ":" ";" _pathlist $ENV{PATH}) + foreach (_pathcomp ${_pathlist}) + get_filename_component(_pathcomp ${_pathcomp} REALPATH) + if (_path STREQUAL _pathcomp) + # This adds a lot of unneccessary flags, but may be useful if there's + # a flag that should be passed to cling. + set(CLING_CXX_RLTV ${_name}) + break() endif() + endforeach() - # If CMAKE_CXX_FLAGS contains --gcc-toolchain= then that should be passed on - string(FIND "${CMAKE_CXX_FLAGS}" "--gcc-toolchain=" cling_gcc_toolchain) - if ("${cling_gcc_toolchain}" GREATER -1) - # TODO Refactor these two into common function - if (CLING_CXX_PATH) - string(FIND "${CLING_CXX_PATH}" "--gcc-toolchain=" cling_gcc_toolchain) - if ("${cling_gcc_toolchain}" EQUAL -1) - set(CLING_CXX_PATH_ARGS "--gcc-toolchain=${gcctoolchain}") - endif() + # FIXME: Perhaps CLING_CXX_RLTV should have a better name? + if(NOT CLING_CXX_RLTV AND NOT CLING_CXX_PATH) + # We got nothing, just use whatever CMake is using. + set(CLING_CXX_PATH ${CMAKE_CXX_COMPILER}) + endif() + + # If CMAKE_CXX_FLAGS contains --gcc-toolchain= then that should be passed on + string(FIND "${CMAKE_CXX_FLAGS}" "--gcc-toolchain=" cling_gcc_toolchain) + if ("${cling_gcc_toolchain}" GREATER -1) + # TODO Refactor these two into common function + if (CLING_CXX_PATH) + string(FIND "${CLING_CXX_PATH}" "--gcc-toolchain=" cling_gcc_toolchain) + if ("${cling_gcc_toolchain}" EQUAL -1) + set(CLING_CXX_PATH_ARGS "--gcc-toolchain=${gcctoolchain}") endif() - if (CLING_CXX_RLTV) - string(FIND "${CLING_CXX_RLTV}" "--gcc-toolchain=" cling_gcc_toolchain) - if ("${cling_gcc_toolchain}" EQUAL -1) - set(CLING_CXX_RLTV "${CLING_CXX_RLTV} --gcc-toolchain=${gcctoolchain}") - endif() + endif() + if (CLING_CXX_RLTV) + string(FIND "${CLING_CXX_RLTV}" "--gcc-toolchain=" cling_gcc_toolchain) + if ("${cling_gcc_toolchain}" EQUAL -1) + set(CLING_CXX_RLTV "${CLING_CXX_RLTV} --gcc-toolchain=${gcctoolchain}") endif() endif() endif() + set(out_compiler_binary ${CLING_CXX_RLTV} PARENT_SCOPE) + set(out_header_path ${CLING_CXX_HEADERS} PARENT_SCOPE) +endfunction(detect_header_location) + + +if (UNIX) + set_source_files_properties(Exception.cpp COMPILE_FLAGS "-fexceptions -frtti") + set_source_files_properties(Interpreter.cpp COMPILE_FLAGS "-fexceptions") + + # Remove all -I from CMAKE_CXX_FLAGS + string(REPLACE ";" " " __flags "${CMAKE_CXX_FLAGS}") + string(REGEX REPLACE "-I[^ ]+" "" CLING_COMPILER_FLAGS_NO_I "${__flags}") + + option(CLING_CXX_PATH "Compiler cling will invoke for c++ headers." "") + option(CLING_CXX_HEADERS "Path cling will use for c++ headers." "") + + if(NOT CLING_CXX_PATH) + detect_header_location(CLING_CXX_PATH CLING_CXX_RLTV) + endif() if(NOT CLING_CXX_HEADERS) if (CLING_CXX_PATH) From 6e9d09a008ac73ee2f3fc55cbbf192cd435eea8e Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Sat, 9 May 2020 18:59:32 +0000 Subject: [PATCH 3/4] [cling] Find C headers and put them in cling-compiledata.h New versions of OSX has libc in the sdk path and not at the usual /usr/include. Detect the location in a similar way to detection of the C++ headers. This solves the issue with the failure to build the Darwin.pcm file and the diagnostic that there is no module.modulemap for osx 10.15 in /usr/include/ --- core/CMakeLists.txt | 8 ++++---- .../cling/lib/Interpreter/CMakeLists.txt | 20 ++++++++++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 72f789e38851c..c8517036d018e 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -168,15 +168,15 @@ if(runtime_cxxmodules) set(libc libc) endif() - ROOT_GENERATE_CXXMODULE(${libc} "/usr/include") - - get_property(cxx_headers_location GLOBAL PROPERTY ROOT_CLING_CXX_HEADERS_LOCATION) + get_property(c_headers_location GLOBAL PROPERTY CLING_C_HEADERS_LOCATION) + ROOT_GENERATE_CXXMODULE(${libc} ${c_headers_location}) + get_property(cxx_headers_location GLOBAL PROPERTY CLING_CXX_HEADERS_LOCATION) # Assume the first component is where the public headers are. string(FIND ${cxx_headers_location} ":" idx) string(SUBSTRING ${cxx_headers_location} 0 ${idx} cxx_headers_location) - ROOT_GENERATE_CXXMODULE(std ${cxx_headers_location} DEPENDENCIES ${libc}) + ROOT_GENERATE_CXXMODULE(Cling_Runtime ${CMAKE_BINARY_DIR}/etc/cling DEPENDENCIES std) ROOT_GENERATE_CXXMODULE(Cling_Runtime_Extra ${CMAKE_BINARY_DIR}/etc/cling DEPENDENCIES Cling_Runtime) diff --git a/interpreter/cling/lib/Interpreter/CMakeLists.txt b/interpreter/cling/lib/Interpreter/CMakeLists.txt index c07fe413cdcb6..12e74a6974a57 100644 --- a/interpreter/cling/lib/Interpreter/CMakeLists.txt +++ b/interpreter/cling/lib/Interpreter/CMakeLists.txt @@ -243,6 +243,22 @@ if (UNIX) string(REPLACE ";" " " __flags "${CMAKE_CXX_FLAGS}") string(REGEX REPLACE "-I[^ ]+" "" CLING_COMPILER_FLAGS_NO_I "${__flags}") + option(CLING_C_PATH "Compiler cling will invoke for c headers." "") + option(CLING_C_HEADERS "Path cling will use for c headers." "") + # FIXME: Merge with detect_header_location + if (NOT CLING_C_HEADERS) + if (APPLE) + execute_process(COMMAND xcrun --show-sdk-path + OUTPUT_VARIABLE OSX_SDK_PATH + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CLING_C_HEADERS ${OSX_SDK_PATH}/usr/include) + else() + set(CLING_C_HEADERS /usr/include) + endif(APPLE) + endif (NOT CLING_C_HEADERS) + + MESSAGE(STATUS "Cling will look for C headers in '${CLING_C_HEADERS}' at runtime.") + option(CLING_CXX_PATH "Compiler cling will invoke for c++ headers." "") option(CLING_CXX_HEADERS "Path cling will use for c++ headers." "") @@ -294,11 +310,13 @@ if (UNIX) # In modules builds we 'mount' our own stl modulemap for libstdc++. In order to do this, # we need to know where is ROOT/cling STL. - set_property(GLOBAL PROPERTY ROOT_CLING_CXX_HEADERS_LOCATION "${CLING_CXX_HEADERS}") + set_property(GLOBAL PROPERTY CLING_C_HEADERS_LOCATION "${CLING_C_HEADERS}") + set_property(GLOBAL PROPERTY CLING_CXX_HEADERS_LOCATION "${CLING_CXX_HEADERS}") # FIXME: We should use file(GENERATE) cmake command. file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/cling-compiledata.h.in " + #define CLING_C_INCL \"${CLING_C_HEADERS}\" #define CLING_CXX_INCL \"${CLING_CXX_HEADERS}\" #define CLING_INCLUDE_PATHS \"${CLING_INCLUDE_PATHS}\" ") From e627c0b22b1a03f2ade5a7ea0cec65d0e4c36a89 Mon Sep 17 00:00:00 2001 From: Vassil Vassilev Date: Mon, 11 May 2020 09:04:44 +0000 Subject: [PATCH 4/4] Fix osx --- cmake/modules/RootMacros.cmake | 8 ++++---- core/dictgen/src/rootcling_impl.cxx | 2 +- interpreter/cling/lib/Interpreter/CIFactory.cpp | 10 ++++++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/cmake/modules/RootMacros.cmake b/cmake/modules/RootMacros.cmake index c3a6033b07eaa..f1f4fc7a5a062 100644 --- a/cmake/modules/RootMacros.cmake +++ b/cmake/modules/RootMacros.cmake @@ -291,13 +291,13 @@ function(ROOT_GENERATE_CXXMODULE module_name headers_location) endif() set(module_file_location ${root_libdir}/${module_name}.pcm) - set(dependencies ${real_modulemap_file}) + set(file_dependencies ${real_modulemap_file}) foreach(dep ${ARG_DEPENDENCIES}) # Turn the target to a file.pcm. This allows us to add it as a file dependency # in the DEPENDS clause of add_custom_command. This is the only way I found # to trigger rebuild of the full chain of dependencies. # Eg: a.pcm <- b.pcm <- c.pcm; rm a.pcm; ninja c.pcm; rebuilds a.pcm and b.pcm - list(APPEND dependencies ${root_libdir}/${dep}.pcm) + list(APPEND file_dependencies ${root_libdir}/${dep}.pcm) endforeach() add_custom_command(OUTPUT ${module_file_location} @@ -306,9 +306,9 @@ function(ROOT_GENERATE_CXXMODULE module_name headers_location) -fmodules -Xclang -emit-module -fmodule-name=${module_name} -fmodules-cache-path=${root_libdir} -o ${module_file_location} ${headers_location}/module.modulemap - DEPENDS ${dependencies}) + DEPENDS ${file_dependencies}) - add_custom_target(${module_name} ALL DEPENDS ${module_file_location} ${dependencies}) + add_custom_target(${module_name} ALL DEPENDS ${module_file_location} ${file_dependencies} ${ARG_DEPENDENCIES}) endfunction(ROOT_GENERATE_CXXMODULE) diff --git a/core/dictgen/src/rootcling_impl.cxx b/core/dictgen/src/rootcling_impl.cxx index 75e1d245427f1..b5ca254af379e 100644 --- a/core/dictgen/src/rootcling_impl.cxx +++ b/core/dictgen/src/rootcling_impl.cxx @@ -4016,7 +4016,7 @@ int RootClingMain(int argc, llvm::sys::path::append(builtinModuleMap, "module.modulemap"); clingArgsC.push_back(resourcePathInc.c_str()); - clingArgsC.push_back("-nobuiltininc"); + //clingArgsC.push_back("-nobuiltininc"); clingArgsC.push_back("-noruntime"); for (const std::string& Opt : gOptBareClingSink) diff --git a/interpreter/cling/lib/Interpreter/CIFactory.cpp b/interpreter/cling/lib/Interpreter/CIFactory.cpp index 2f0bc5dec58c5..7b82f4b0426fe 100644 --- a/interpreter/cling/lib/Interpreter/CIFactory.cpp +++ b/interpreter/cling/lib/Interpreter/CIFactory.cpp @@ -42,6 +42,7 @@ #include "llvm/Config/llvm-config.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Host.h" #include "llvm/Support/MemoryBuffer.h" @@ -1144,8 +1145,13 @@ static void stringifyPreprocSetting(PreprocessorOptions& PPOpts, StringRef CurInput = FrontendOpts.Inputs[0].getFile(); Out << "Information for module file '" << CurInput << "':\n"; auto &FileMgr = CI.getFileManager(); - auto Buffer = FileMgr.getBufferForFile(CurInput); - StringRef Magic = (*Buffer)->getMemBufferRef().getBuffer(); + auto BufferOrErr = FileMgr.getBufferForFile(CurInput); + + if (!BufferOrErr) + cling::errs() << "Error creating a buffer for file '" + << BufferOrErr.getError().message() << "'\n"; + + StringRef Magic = (*BufferOrErr)->getMemBufferRef().getBuffer(); bool IsRaw = (Magic.size() >= 4 && Magic[0] == 'C' && Magic[1] == 'P' && Magic[2] == 'C' && Magic[3] == 'H'); Out << " Module format: " << (IsRaw ? "raw" : "obj") << "\n";