- For the ARM target, C-language intrinsics ``<arm_cde.h>`` for the CDE
instruction set are now provided.
-* clang adds support for a set of extended integer types (``_ExtInt(N)``) that
+- clang adds support for a set of extended integer types (``_ExtInt(N)``) that
permit non-power of 2 integers, exposing the LLVM integer types. Since a major
motivating use case for these types is to limit 'bit' usage, these types don't
automatically promote to 'int' when operations are done between two ``ExtInt(N)``
types, instead math occurs at the size of the largest ``ExtInt(N)`` type.
+- Users of UBSan, PGO, and coverage on Windows will now need to add clang's
+ library resource directory to their library search path. These features all
+ use runtime libraries, and Clang provides these libraries in its resource
+ directory. For example, if LLVM is installed in ``C:\Program Files\LLVM``,
+ then the profile runtime library will appear at
+ ``C:\Program Files\LLVM\lib\clang\11.0.0\lib\windows\clang_rt.profile-x86_64.lib``.
+ To ensure that the linker can find the appropriate library, users should pass
+ ``/LIBPATH:C:\Program Files\LLVM\lib\clang\11.0.0\lib\windows`` to the
+ linker. If the user links the program with the ``clang`` or ``clang-cl``
+ drivers, the driver will pass this flag for them.
New Compiler Flags
clang-cl cannot successfully compile all the files. clang-cl may fail to compile
a file either because it cannot generate code for some C++ feature, or because
it cannot parse some Microsoft language extension.
+
+Finding Clang runtime libraries
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+clang-cl supports several features that require runtime library support:
+
+- Address Sanitizer (ASan): ``-fsanitize=address``
+- Undefined Behavior Sanitizer (UBSan): ``-fsanitize=undefined``
+- Code coverage: ``-fprofile-instr-generate -fcoverage-mapping``
+- Profile Guided Optimization (PGO): ``-fprofile-instr-generate``
+- Certain math operations (int128 division) require the builtins library
+
+In order to use these features, the user must link the right runtime libraries
+into their program. These libraries are distributed alongside Clang in the
+library resource directory. Clang searches for the resource directory by
+searching relative to the Clang executable. For example, if LLVM is installed
+in ``C:\Program Files\LLVM``, then the profile runtime library will be located
+at the path
+``C:\Program Files\LLVM\lib\clang\11.0.0\lib\windows\clang_rt.profile-x86_64.lib``.
+
+For UBSan, PGO, and coverage, Clang will emit object files that auto-link the
+appropriate runtime library, but the user generally needs to help the linker
+(whether it is ``lld-link.exe`` or MSVC ``link.exe``) find the library resource
+directory. Using the example installation above, this would mean passing
+``/LIBPATH:C:\Program Files\LLVM\lib\clang\11.0.0\lib\windows`` to the linker.
+If the user links the program with the ``clang`` or ``clang-cl`` drivers, the
+driver will pass this flag for them.
+
+If the linker cannot find the appropriate library, it will emit an error like
+this::
+
+ $ clang-cl -c -fsanitize=undefined t.cpp
+
+ $ lld-link t.obj -dll
+ lld-link: error: could not open 'clang_rt.ubsan_standalone-x86_64.lib': no such file or directory
+ lld-link: error: could not open 'clang_rt.ubsan_standalone_cxx-x86_64.lib': no such file or directory
+
+ $ link t.obj -dll -nologo
+ LINK : fatal error LNK1104: cannot open file 'clang_rt.ubsan_standalone-x86_64.lib'
+
+To fix the error, add the appropriate ``/libpath:`` flag to the link line.
+
+For ASan, as of this writing, the user is also responsible for linking against
+the correct ASan libraries.
+
+If the user is using the dynamic CRT (``/MD``), then they should add
+``clang_rt.asan_dynamic-x86_64.lib`` to the link line as a regular input. For
+other architectures, replace x86_64 with the appropriate name here and below.
+
+If the user is using the static CRT (``/MT``), then different runtimes are used
+to produce DLLs and EXEs. To link a DLL, pass
+``clang_rt.asan_dll_thunk-x86_64.lib``. To link an EXE, pass
+``-wholearchive:clang_rt.asan-x86_64.lib``.
getCompilerRTArgString(const llvm::opt::ArgList &Args, StringRef Component,
FileType Type = ToolChain::FT_Static) const;
+ std::string getCompilerRTBasename(const llvm::opt::ArgList &Args,
+ StringRef Component,
+ FileType Type = ToolChain::FT_Static,
+ bool AddArch = true) const;
+
// Returns target specific runtime path if it exists.
virtual Optional<std::string> getRuntimePath() const;
if (TC.getTriple().isOSWindows() && needsUbsanRt()) {
// Instruct the code generator to embed linker directives in the object file
// that cause the required runtime libraries to be linked.
- CmdArgs.push_back(Args.MakeArgString(
- "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone")));
+ CmdArgs.push_back(
+ Args.MakeArgString("--dependent-lib=" +
+ TC.getCompilerRTBasename(Args, "ubsan_standalone")));
if (types::isCXX(InputType))
CmdArgs.push_back(Args.MakeArgString(
- "--dependent-lib=" + TC.getCompilerRT(Args, "ubsan_standalone_cxx")));
+ "--dependent-lib=" +
+ TC.getCompilerRTBasename(Args, "ubsan_standalone_cxx")));
}
if (TC.getTriple().isOSWindows() && needsStatsRt()) {
- CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
- TC.getCompilerRT(Args, "stats_client")));
+ CmdArgs.push_back(Args.MakeArgString(
+ "--dependent-lib=" + TC.getCompilerRTBasename(Args, "stats_client")));
// The main executable must export the stats runtime.
// FIXME: Only exporting from the main executable (e.g. based on whether the
// translation unit defines main()) would save a little space, but having
// multiple copies of the runtime shouldn't hurt.
- CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
- TC.getCompilerRT(Args, "stats")));
+ CmdArgs.push_back(Args.MakeArgString(
+ "--dependent-lib=" + TC.getCompilerRTBasename(Args, "stats")));
addIncludeLinkerOption(TC, Args, CmdArgs, "__sanitizer_stats_register");
}
return std::string(Path.str());
}
-std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component,
- FileType Type) const {
+std::string ToolChain::getCompilerRTBasename(const ArgList &Args,
+ StringRef Component, FileType Type,
+ bool AddArch) const {
const llvm::Triple &TT = getTriple();
bool IsITANMSVCWindows =
TT.isWindowsMSVCEnvironment() || TT.isWindowsItaniumEnvironment();
break;
}
+ std::string ArchAndEnv;
+ if (AddArch) {
+ StringRef Arch = getArchNameForCompilerRTLib(*this, Args);
+ const char *Env = TT.isAndroid() ? "-android" : "";
+ ArchAndEnv = ("-" + Arch + Env).str();
+ }
+ return (Prefix + Twine("clang_rt.") + Component + ArchAndEnv + Suffix).str();
+}
+
+std::string ToolChain::getCompilerRT(const ArgList &Args, StringRef Component,
+ FileType Type) const {
+ // Check for runtime files in the new layout without the architecture first.
+ std::string CRTBasename =
+ getCompilerRTBasename(Args, Component, Type, /*AddArch=*/false);
for (const auto &LibPath : getLibraryPaths()) {
SmallString<128> P(LibPath);
- llvm::sys::path::append(P, Prefix + Twine("clang_rt.") + Component + Suffix);
+ llvm::sys::path::append(P, CRTBasename);
if (getVFS().exists(P))
return std::string(P.str());
}
- StringRef Arch = getArchNameForCompilerRTLib(*this, Args);
- const char *Env = TT.isAndroid() ? "-android" : "";
+ // Fall back to the old expected compiler-rt name if the new one does not
+ // exist.
+ CRTBasename = getCompilerRTBasename(Args, Component, Type, /*AddArch=*/true);
SmallString<128> Path(getCompilerRTPath());
- llvm::sys::path::append(Path, Prefix + Twine("clang_rt.") + Component + "-" +
- Arch + Env + Suffix);
+ llvm::sys::path::append(Path, CRTBasename);
return std::string(Path.str());
}
CmdArgs.push_back("-fprofile-instrument=clang");
if (TC.getTriple().isWindowsMSVCEnvironment()) {
// Add dependent lib for clang_rt.profile
- CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
- TC.getCompilerRT(Args, "profile")));
+ CmdArgs.push_back(Args.MakeArgString(
+ "--dependent-lib=" + TC.getCompilerRTBasename(Args, "profile")));
}
}
}
if (PGOGenArg) {
if (TC.getTriple().isWindowsMSVCEnvironment()) {
- CmdArgs.push_back(Args.MakeArgString("--dependent-lib=" +
- TC.getCompilerRT(Args, "profile")));
+ // Add dependent lib for clang_rt.profile
+ CmdArgs.push_back(Args.MakeArgString(
+ "--dependent-lib=" + TC.getCompilerRTBasename(Args, "profile")));
}
if (PGOGenArg->getOption().matches(
PGOGenerateArg ? options::OPT_fprofile_generate_EQ
Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath));
}
+ // Add the compiler-rt library directories to libpath if they exist to help
+ // the linker find the various sanitizer, builtin, and profiling runtimes.
+ for (const auto &LibPath : TC.getLibraryPaths()) {
+ if (TC.getVFS().exists(LibPath))
+ CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
+ }
+ auto CRTPath = TC.getCompilerRTPath();
+ if (TC.getVFS().exists(CRTPath))
+ CmdArgs.push_back(Args.MakeArgString("-libpath:" + CRTPath));
+
if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L))
for (const auto &LibPath : Args.getAllArgValues(options::OPT_L))
CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath));
// RUN: %clang_cl -### /FA -fprofile-instr-generate -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-INSTR-GENERATE %s
// RUN: %clang_cl -### /FA -fprofile-instr-generate=/tmp/somefile.profraw -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-INSTR-GENERATE-FILE %s
-// CHECK-PROFILE-INSTR-GENERATE: "-fprofile-instrument=clang" "--dependent-lib={{[^"]*}}clang_rt.profile-{{[^"]*}}.lib"
+// CHECK-PROFILE-INSTR-GENERATE: "-fprofile-instrument=clang" "--dependent-lib=clang_rt.profile-{{[^"]*}}.lib"
// CHECK-PROFILE-INSTR-GENERATE-FILE: "-fprofile-instrument-path=/tmp/somefile.profraw"
// RUN: %clang_cl -### /FA -fprofile-generate -- %s 2>&1 | FileCheck -check-prefix=CHECK-PROFILE-GENERATE %s
-// CHECK-PROFILE-GENERATE: "-fprofile-instrument=llvm" "--dependent-lib={{[^"]*}}clang_rt.profile-{{[^"]*}}.lib"
+// CHECK-PROFILE-GENERATE: "-fprofile-instrument=llvm" "--dependent-lib=clang_rt.profile-{{[^"]*}}.lib"
// RUN: %clang_cl -### /FA -fprofile-instr-generate -fprofile-instr-use -- %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s
// RUN: %clang_cl -### /FA -fprofile-instr-generate -fprofile-instr-use=file -- %s 2>&1 | FileCheck -check-prefix=CHECK-NO-MIX-GEN-USE %s
// RUN: -target x86_64-pc-windows \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-WIN64 %s
-// CHECK-CFI-STATS-WIN64: "--dependent-lib={{[^"]*}}clang_rt.stats_client-x86_64.lib"
-// CHECK-CFI-STATS-WIN64: "--dependent-lib={{[^"]*}}clang_rt.stats-x86_64.lib"
+// CHECK-CFI-STATS-WIN64: "--dependent-lib=clang_rt.stats_client-x86_64.lib"
+// CHECK-CFI-STATS-WIN64: "--dependent-lib=clang_rt.stats-x86_64.lib"
// CHECK-CFI-STATS-WIN64: "--linker-option=/include:__sanitizer_stats_register"
// RUN: %clang -fsanitize=cfi -fsanitize-stats %s -### -o %t.o 2>&1 \
// RUN: -target i686-pc-windows \
// RUN: --sysroot=%S/Inputs/basic_linux_tree \
// RUN: | FileCheck --check-prefix=CHECK-CFI-STATS-WIN32 %s
-// CHECK-CFI-STATS-WIN32: "--dependent-lib={{[^"]*}}clang_rt.stats_client-i386.lib"
-// CHECK-CFI-STATS-WIN32: "--dependent-lib={{[^"]*}}clang_rt.stats-i386.lib"
+// CHECK-CFI-STATS-WIN32: "--dependent-lib=clang_rt.stats_client-i386.lib"
+// CHECK-CFI-STATS-WIN32: "--dependent-lib=clang_rt.stats-i386.lib"
// CHECK-CFI-STATS-WIN32: "--linker-option=/include:___sanitizer_stats_register"
// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \
endif()
endif()
+# When using clang-cl with an instrumentation-based tool, add clang's library
+# resource directory to the library search path. Because cmake invokes the
+# linker directly, it isn't sufficient to pass -fsanitize=* to the linker.
+if (CLANG_CL AND (LLVM_BUILD_INSTRUMENTED OR LLVM_USE_SANITIZER))
+ execute_process(
+ COMMAND ${CMAKE_CXX_COMPILER} /clang:-print-resource-dir
+ OUTPUT_VARIABLE clang_resource_dir
+ ERROR_VARIABLE clang_cl_stderr
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_STRIP_TRAILING_WHITESPACE
+ RESULT_VARIABLE clang_cl_exit_code)
+ if (NOT "${clang_cl_exit_code}" STREQUAL "0")
+ message(FATAL_ERROR
+ "Unable to invoke clang-cl to find resource dir: ${clang_cl_stderr}")
+ endif()
+ file(TO_CMAKE_PATH "${clang_resource_dir}" clang_resource_dir)
+ append("/libpath:${clang_resource_dir}/lib/windows"
+ CMAKE_EXE_LINKER_FLAGS
+ CMAKE_SHARED_LINKER_FLAGS)
+endif()
+
if(LLVM_PROFDATA_FILE AND EXISTS ${LLVM_PROFDATA_FILE})
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
append("-fprofile-instr-use=\"${LLVM_PROFDATA_FILE}\""