如何在CMake for Clang中手动禁用libstdc++

6jygbczu  于 2023-05-02  发布在  其他
关注(0)|答案(1)|浏览(174)

最近,我正在使用CMake和llvmClang以及Visual Studio Code为一个程序配置一个新的C和C项目,该程序生成或依赖的每个确切对象或库都需要显式指定要生成或链接。设计的程序应具有高RAM效率,安全性最低的漏洞所引起的未使用的数据段和交叉编译。
也就是说,用于架构、应用程序二进制接口(aka ABI)、来自C和C
标准的标准库函数以及可执行二进制的供应库需要手动设置,以便工具链程序以适当的方式处理。
好吧,我认为用libc库替换libstdc是一个很好的“切入点”,但绝对不是直接的,你可能已经从其他地方记录的痛苦实践中学到了足够多的东西,并认为这是一个坏主意。但很抱歉这已经成了我的执念我真的很感谢你的帮助,在它把我逼疯之前。
无论如何,下面是关于我的本地机器的信息列表:

  • Ubuntu 20.04@v5。13.0-40-通用内核,SMP,x86_64指令集
  • CMake 3.23.1,从源代码构建
  • gcc-10:amd64
  • clang-12:amd64
  • libstdc++-10-dev:amd64
  • libc++-12-dev:amd64

从命令返回时,Clang工作正常:
jacob.nielson@ubuntu~$:clang++-12 -v -c -xc /dev/null

为了使新项目尽可能避免将来出现任何意外和不相关的问题,我在创建CMakeLists之前尽可能简单地保留了项目目录布局。文本:

开始,我在CMake的文档中查找了关于编译(预处理)或链接选项的信息:

-"-nostdinc"
-"-nostdinc++"
-"-nobuiltininc"
-"-nostdlib"
-"-nolibc"
-"-nostdlib++"
-"-nodefaultlibs"

然后我在CMakeLists中提出了几行简单的代码。文本:

cmake_minimum_required(VERSION 3.23.0)
  project(program VERSION 0.0.1)
  set(TARGET program)

  add_compile_options(-std=c++17)

  # I'm not sure about semantics of "-nostdinc++", "-nostdinc" and "-nobuiltininc". 
  # Should I add them all in case to substitute libstdc++ with libc++ or not in below?
  add_compile_options($<$<COMPILE_LANG_AND_ID:CXX,Clang>:-nobuiltininc>)
  add_compile_options($<$<COMPILE_LANG_AND_ID:CXX,Clang>:-nostdinc++>)
  add_compile_options($<$<COMPILE_LANG_AND_ID:CXX,Clang>:-nostdinc>)

  # Should I add path to system headers in "-isystem" option? 
  # Attention: cmake-generator-expression does not recognize white-space separated options group to be string. It is option "-isystem" where the path to directory as value follows without white-space in this example.
  add_compile_options(
      $<$<COMPILE_LANG_AND_ID:CXX,Clang>:-isystem/usr/include/x86_64-linux-gnu>
      $<$<COMPILE_LANG_AND_ID:CXX,Clang>:-isystem-after/usr/include>
      # "-cxx-isystem" option is legacy and is not appropriate for standard headers. Add path to the subdirectories where you put your own c++-only headers in your project.
      $<$<COMPILE_LANG_AND_ID:CXX,Clang>:-cxx-isystem ${...}>
  )

  # If C or/and C++ standard library is turned off like in above, Should I add path to libc++ headers in "-stdlib++-isystem" option?
  # Attention: cmake-generator-expression does not recognize white-space separated options group to be string. It is option "-stdlib++-isystem" where the path to directory as value follows without white-space in this example.
  add_compile_options($<$<COMPILE_LANG_AND_ID:CXX,Clang>:-stdlib++-isystem/usr/lib/llvm-12/include/c++/v1>) 

  # Replace default C++ standard with libc++.
  add_link_options(
      $<$<LINK_LANG_AND_ID:CXX,Clang>:-stdlib=libc++>
  )

  add_executable(${TARGET} "${CMAKE_CURRENT_SOURCE_DIR}/source/${TARGET}.cpp")
  target_link_libraries(${TARGET} PRIVATE
      $<$<LINK_LANG_AND_ID:CXX,Clang>:c++> 
      $<$<LINK_LANG_AND_ID:CXX,Clang>:c++abi>
      $<$<LINK_LANG_AND_ID:CXX,Clang>:unwind>
      $<$<LINK_LANG_AND_ID:CXX,Clang>:ssl>
      $<$<LINK_LANG_AND_ID:CXX,Clang>:crypto>
      $<$<LINK_LANG_AND_ID:CXX,Clang>:pthread>
      )

接下来,我尝试为项目生成“Unix Makefile”:

CMake解析成功:

同时在./build/CMakeFiles/3.23.1/临时文件夹中生成CMakeCCompiler.cmakeCMakeCXXCompiler.cmake,后者包含几行:

set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "/usr/include/c++/10;/usr/include/x86_64-linux-gnu/c++/10;/usr/include/c++/10/backward;/usr/local/include;/usr/lib/llvm-12/lib/clang/12.0.0/include;/usr/include/x86_64-linux-gnu;/usr/include")
    set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "stdc++;m;gcc_s;gcc;c;gcc_s;gcc")
    set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "/usr/lib/gcc/x86_64-linux-gnu/10;/usr/lib/x86_64-linux-gnu;/usr/lib64;/lib/x86_64-linux-gnu;/lib64;/usr/lib;/usr/lib/llvm-12/lib;/lib")
    set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "")

注意:Clang使用启发式发现来搜索前端报告的目录中的标题。这是不合适的,因为我只是不想在项目中隐式地使用libstdc++的头文件或库。
此外,它还将编译命令导出到compile_commands.json中,如下所示:

/usr/bin/clang++-12 -DLIBCXXABI_USE_COMPILER_RT=YES -DLIBCXX_USE_COMPILER_RT=YES -I/data/solution/projects/program/include -std=c++17 -stdlib=libc++ -isystem /usr/include/x86_64-linux-gnu -stdlib++-isystem /usr/lib/llvm-12/include/c++/v1 -o CMakeFiles/program.dir/source/program.cpp.o -c /data/solution/projects/program/source/program.cpp

看起来都不错但是当我使用ldd检查时:
jacob.nielson@ubuntu:/data/solution/projects/program/build/debug$ ldd program

linux-vdso.so.1 (0x00007ffee7190000)
    libc++.so.1 => /lib/x86_64-linux-gnu/libc++.so.1 (0x00007f69164a5000)
    libc++abi.so.1 => /lib/x86_64-linux-gnu/libc++abi.so.1 (0x00007f691646d000)
    libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f691628b000)     /* LIBSTDC++ in here! */
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f691613c000)               /* LIBM in here */
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f6916121000)       /* gcc startup file in here! */
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6915f2f000)               /* LIBC in here! */
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f6915f0a000)
    librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f6915f00000)
    libatomic.so.1 => /lib/x86_64-linux-gnu/libatomic.so.1 (0x00007f6915ef6000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f691658d000)

看到所有的libstdc++、libc、libm或libgcc_s仍然存在,这是令人沮丧的。我是否错过了任何静态链接它们的选项,比如GNU CC中的-static-libc,或者我必须在这一点上给予我的野心?

xdnvmnnf

xdnvmnnf1#

现将对问题的答复记录在案。
这里有一个关于**missing定义的错误,指示Clang使用compiler_rt。**我添加了相关选项后,问题就解决了。
至于用libc替换libstsdc,不要忘记添加以下选项:

add_compile_definitions(
    $<$<COMPILE_LANG_AND_ID:CXX,Clang>:LLVM_ENABLE_RUNTIMES=libunwind>
    $<$<COMPILE_LANG_AND_ID:CXX,Clang>:LIBCXX_USE_COMPILER_RT=YES>
    $<$<COMPILE_LANG_AND_ID:CXX,Clang>:LIBCXXABI_USE_COMPILER_RT=YES>
    $<$<COMPILE_LANG_AND_ID:CXX,Clang>:LIBUNWIND_USE_COMPILER_RT=YES>
    )

add_link_options(
    $<$<LINK_LANG_AND_ID:CXX,Clang>:-stdlib=libc++>
    $<$<LINK_LANG_AND_ID:CXX,Clang>:-rtlib=compiler-rt>
    )

AFAK,上面的定义有助于指示clang“不要链接到默认库”,但也必须将它们与编译选项“-stdlib=libc++”结合使用,特别是**NO“-nostdlib”**才能使替换生效。本文件的部分内容如下:

编译器运行时

默认的运行时库是特定于目标的。对于GCC是主要编译器的目标,Clang当前默认使用libgcc_s。在大多数其他目标上,默认情况下使用compiler-rt。
然而,我还不清楚这里的目标指的是什么,以及如何判断编译器对于给定的目标是主导的。

相关问题