Dump Compiler Options
Inspect and dump mainstream compilers(gcc/clang/msvc) predefined macros, c/c++ language standard and search paths.
Predefined macros#
Pre-defined C/C++ Compiler Macros
Guide to predefined macros in C++ compilers (gcc, clang, msvc etc.)
gnu/gcc#
Predefined Macros (The C Preprocessor)
Invocation (The C Preprocessor): You can invoke the preprocessor either with the cpp
command, or via gcc -E
.
-dletters
: Says to make debugging dumps during compilation as specified by letters.
-dM
Instead of the normal output, generate a list of ‘#define’ directives for all the macros defined during the execution of the preprocessor, including predefined macros. This gives you a way of finding out what is predefined in your version of the preprocessor. Assuming you have no file foo.h, the command
touch foo.h; cpp -dM foo.h
shows all the predefined macros.
g++ - GCC dump preprocessor defines - Stack Overflow
echo 空流预编译:
# echo | cpp -dM
# echo | gcc -E -dM -
# echo | g++ -E -dM -
$ echo | gcc -x c -E -dM -
$ echo | g++ -x c++ -E -dM -
或指定空文件 /dev/null 预编译:
# cpp -dM - < /dev/null
# gcc -E -dM - < /dev/null
$ gcc -x c -E -dM - < /dev/null
$ gcc -x c++ -E -dM - < /dev/null
# or
$ gcc -x c -E -dM /dev/null
$ gcc -x c++ -E -dM /dev/null
包含特定头文件:
$ echo "#include <stdio.h>" | cpp -dM
# cpp -dM -include sys/socket.h < /dev/null
$ gcc -E -dM -include sys/socket.h - < /dev/null
指定C++版本:
clang/llvm#
在 macOS 上,gcc/g++ 是 XcodeDefault.xctoolchain 下 clang/clang++ 的 shims or wrapper executables。
clang 兼容 gcc 大部分常规命令,可替代 gcc 执行 -E -dM
预处理命令,输出预定义宏。
clang 还可通过 -target
/ -arch
选项指定 Cross-Compilation 的目标 CPU 架构,输出对应 CPU 下的一些预定义宏。
clang -print-targets 和
objdump --version
输出 Registered Targets。
clang --print-supported-cpus 列出指定 target 支持的处理器。
IA32(_ILP32)/IA64(_LP64):
ARM32(_ILP32)/ARM64(_LP64):
可以通过管道导给 grep 过滤不同 CPU 架构下 __SIZEOF_INT__
,__SIZEOF_LONG__
,__SIZEOF_POINTER__
,__BYTE_ORDER__
,__BIGGEST_ALIGNMENT__
等预定义宏。
msvc#
Preprocessor
Predefined macros
/P (Preprocess to a File)
Preprocesses C and C++ source files and writes the preprocessed output to a file.
The following command line preprocesses ADD.C
, preserves comments, adds #line directives, and writes the result to a file, ADD.I
:
c++ - How to find out cl.exe's built-in macros - Stack Overflow
/P
preprocessor flag will emit the currently active macros based on the project build settings. I am not sure if it is exactly the equivalent of gcc command you have shown. The output is in .I
file.
echo // > foo.cpp; cl /Zc:preprocessor /PD foo.cpp
# For C
echo // > foo.cpp; cl /nologo /Zc:preprocessor /PD /EHs /TC foo.cpp | sort; rm foo.cpp, foo.obj
# For C++
echo // > foo.cpp; cl /nologo /Zc:preprocessor /PD /EHs /TP foo.cpp | sort; rm foo.cpp, foo.obj
c/c++ standard#
gnu/gcc#
gcc - How can I tell what standard my C is in? - Software Engineering Stack Exchange
Language Standards Supported by GCC
2.1 C Language: The default, if no C language dialect options are given, is
-std=gnu17
.
2.2 C++ Language: The default, if no C++ language dialect options are given, is-std=gnu++17
.
$ gcc --version
gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ man gcc | grep -e "-std=c++"
-std=c++98.
GNU dialect of -std=c++98.
GNU dialect of -std=c++11. The name gnu++0x is deprecated.
GNU dialect of -std=c++14. The name gnu++1y is deprecated.
GNU dialect of -std=c++17. This is the default for C++ code. The name gnu++1z
GNU dialect of -std=c++20. Support is experimental, and could change in
GNU dialect of -std=c++2b. Support is highly experimental, and will almost
This flag is enabled by default for -std=c++17.
$ man g++ | grep "This is the default for C++ code"
GNU dialect of -std=c++17. This is the default for C++ code. The name gnu++1z
Which C++ standard is the default when compiling with g++? - Stack Overflow
You can also check with gdb
:
- $ g++ -g hello.cpp : Compile program with -g flag to generate debug info
- $ gdb a.out : Debug program with gdb
- (gdb) b main : Put a breakpoint at main
- (gdb) r : Run program (will pause at breakpoint)
- (gdb) info source - lldb 没有 info 命令
Prints out something like:
(gdb) info source
Current source file is hello.cpp
Compilation directory is /home/pifan/Projects/cpp
Located in /home/pifan/Projects/cpp/hello.cpp
Contains 7 lines.
Source language is c++.
Producer is GNU C++17 11.4.0 -mlittle-endian -mabi=lp64 -g -fasynchronous-unwind-tables -fstack-protector-strong -fstack-clash-protection.
Compiled with DWARF 5 debugging format.
Does not include preprocessor macro info.
(gdb) exit
$ gcc -x c -E -dM /dev/null | grep -F __STDC_VERSION__
#define __STDC_VERSION__ 201710L
$ g++ -x c++ -E -dM /dev/null | grep -F __cplusplus
#define __cplusplus 201703L
If you feel like finding it out empirically without reading any manuals.
- Standard Predefined Macros 中有关于
__STDC_VERSION__
和__cplusplus
的说明。 - Common Predefined Macros 有关于宏
__STRICT_ANSI__
的说明。
rpi4b-ubuntu 下输出结果如下:
STDC_VERSION & STRICT_ANSI
./stdc.sh
Linux rpi4b-ubuntu 5.15.0-1053-raspi #56-Ubuntu SMP PREEMPT Mon Apr 15 18:50:10 UTC 2024 aarch64 aarch64 aarch64 GNU/Linux
gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
c89
__STRICT_ANSI__
c99
__STDC_VERSION__ = 199901
__STRICT_ANSI__
c11
__STDC_VERSION__ = 201112
__STRICT_ANSI__
c17
__STDC_VERSION__ = 201710
__STRICT_ANSI__
gnu89
gnu99
__STDC_VERSION__ = 199901
gnu11
__STDC_VERSION__ = 201112
gnu17
rpi4b-ubuntu 下输出结果如下:
cplusplus & __STRICT_ANSI
./stdcpp.sh
Linux rpi4b-ubuntu 5.15.0-1053-raspi #56-Ubuntu SMP PREEMPT Mon Apr 15 18:50:10 UTC 2024 aarch64 aarch64 aarch64 GNU/Linux
g++ (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
c++98
199711
__STRICT_ANSI__
c++11
201103
__STRICT_ANSI__
c++14
201402
__STRICT_ANSI__
c++17
201703
__STRICT_ANSI__
gnu++98
199711
gnu++11
201103
gnu++14
201402
gnu++17
201703
default
201703
clang/llvm#
If no -std option is specified, clang defaults to
gnu17
mode.
Clang - C++ Programming Language Status
C++17 implementation status:
Clang 5 and later implement all the features of the ISO C++ 2017 standard.
By default, Clang 16 or later builds C++ code according to theC++17
standard.
$ man clang | grep -F default
The default C language standard is gnu17, except on PS4, where
The default C++ language standard is gnu++98.
libc++ woes with Xcode 14 | Apple Developer Forums
gcc -E -dM -x c /dev/null | grep -F __STDC_VERSION__
#define __STDC_VERSION__ 201710L
g++ -E -dM -x c++ /dev/null | grep -F __cplusplus
#define __cplusplus 199711L
mbpa2991/macOS_Sonoma 下执行 ./stdc.sh
输出:
STDC_VERSION & STRICT_ANSI
$ ./stdc.sh
Darwin mbpa2991.local 23.5.0 Darwin Kernel Version 23.5.0: Sat Apr 13 17:29:54 PDT 2024; root:xnu-10063.120.104~34/RELEASE_ARM64_T6031 arm64
Apple clang version 15.0.0 (clang-1500.3.9.4)
Target: arm64-apple-darwin23.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
c89
__STRICT_ANSI__
c99
__STDC_VERSION__ = 199901
__STRICT_ANSI__
c11
__STDC_VERSION__ = 201112
__STRICT_ANSI__
c17
__STDC_VERSION__ = 201710
__STRICT_ANSI__
gnu89
gnu99
__STDC_VERSION__ = 199901
gnu11
__STDC_VERSION__ = 201112
gnu17
__STDC_VERSION__ = 201710
default
__STDC_VERSION__ = 201710
mbpa2991/macOS_Sonoma 下执行 ./stdcpp.sh
输出:
cplusplus & __STRICT_ANSI
$ ./stdcpp.sh
Darwin mbpa2991.local 23.5.0 Darwin Kernel Version 23.5.0: Sat Apr 13 17:29:54 PDT 2024; root:xnu-10063.120.104~34/RELEASE_ARM64_T6031 arm64
Apple clang version 15.0.0 (clang-1500.3.9.4)
Target: arm64-apple-darwin23.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
c++98
199711
__STRICT_ANSI__
c++11
201103
__STRICT_ANSI__
c++14
201402
__STRICT_ANSI__
c++17
201703
__STRICT_ANSI__
gnu++98
199711
gnu++11
201103
gnu++14
201402
gnu++17
201703
default
199711
_LIBCPP_VERSION#
⚙ D134187 [libc++] Document the format of _LIBCPP_VERSION
_LIBCPP_VERSION
represents the version of libc++, which matches the version of LLVM.
Given a LLVM release LLVM XX.Y.ZZ (e.g. LLVM 16.0.1 == 16.0.01), _LIBCPP_VERSION is defined to XXYZZ.
⚙ D26062 Alternative solution for detecting libc++'s version.
XCode now defaults to C++20 : r/cpp
执行 grep 搜索 _LIBCPP_VERSION
的定义:
_LIBCPP_VERSION
$ cmdpath=/Library/Developer/CommandLineTools
$ grep -R -H "#define _LIBCPP_VERSION" $cmdpath 2>/dev/null
/Library/Developer/CommandLineTools/usr/include/c++/v1/__config:#define _LIBCPP_VERSION 11000
/Library/Developer/CommandLineTools/usr/include/c++/v1/version:#define _LIBCPP_VERSIONH
/Library/Developer/CommandLineTools/usr/include/c++/v1/__cxx_version:#define _LIBCPP_VERSIONH
/Library/Developer/CommandLineTools/SDKs/MacOSX11.3.sdk/usr/include/c++/v1/__config:#define _LIBCPP_VERSION 12000
/Library/Developer/CommandLineTools/SDKs/MacOSX11.3.sdk/usr/include/c++/v1/version:#define _LIBCPP_VERSIONH
/Library/Developer/CommandLineTools/SDKs/MacOSX13.3.sdk/usr/include/c++/v1/version:#define _LIBCPP_VERSIONH
/Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk/usr/include/c++/v1/version:#define _LIBCPP_VERSIONH
$ xcdevpath=`xcode-select -p`
$ grep -R -H "#define _LIBCPP_VERSION" $xcdevpath 2>/dev/null
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/c++/v1/version:#define _LIBCPP_VERSIONH
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/version:#define _LIBCPP_VERSIONH
c++ - How to detect the libstdc++ version in Clang? - Stack Overflow
#include <iostream>
#include <string>
using namespace std;
int main(int argc, const char * argv[])
{
cout<<"_LIBCPP_VERSION = "<<_LIBCPP_VERSION<<endl;
return 0;
}
clang 15.0.0 下输出 _LIBCPP_VERSION = 170006。
# c++/g++/clang++
$ clang++ libcpp_version.cpp -o libcpp_version && ./libcpp_version
_LIBCPP_VERSION = 170006
msvc#
_MSVC_LANG
Defined as an integer literal that specifies the C++ language standard targeted by the compiler. It's set only in code compiled as C++. The macro is the integer literal value 201402L
by default, or when the /std:c++14
compiler option is specified. .
/std (Specify Language Standard Version)
C standards support: You can invoke the Microsoft C compiler by using the /TC or /Tc compiler option. It's used by default for code that has a .c
file extension, unless overridden by a /TP
or /Tp
option. The default C compiler (that is, the compiler when /std:c11
or /std:c17
isn't specified) implements ANSI C89, but includes several Microsoft extensions, some of which are part of ISO C99.
C++ standards support: The /std
option in effect during a C++ compilation can be detected by use of the _MSVC_LANG preprocessor macro. For more information, see Preprocessor Macros.
Important
Because some existing code depends on the value of the macro __cplusplus
being 199711L
, the MSVC compiler doesn't change the value of this macro unless you explicitly opt in by setting /Zc:__cplusplus. Specify /Zc:__cplusplus
and the /std
option to set __cplusplus
to the appropriate value.
The /std:c++14
option enables C++14 standard-specific features implemented by the MSVC compiler. This option is the default for code compiled as C++. It's available starting in Visual Studio 2015 Update 3.
Search Paths#
Header Search Paths#
Preprocessor Options: -dI
: Output ‘#include’ directives in addition to the result of preprocessing.
运行 clang -v -x c -E /dev/null
或 clang -v -x c++ -E /dev/null
执行预处理,可以查看 C/C++ 语言的 Header Search Paths。
#include "..." search starts here:
#include <...> search starts here:
/usr/local/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/15.0.0/include
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
End of search list.
If you want to see your header include paths for libstdc++
and libc++
, do this:
# GNU C++ runtime
$ echo | clang -x c++ -Wp,-v -stdlib=libstdc++ -fsyntax-only -
# LLVM C++ runtime
$ echo | clang -x c++ -Wp,-v -stdlib=libc++ -fsyntax-only -
涉及到两个选项:
- Preprocessor Options -
-Wp,option
: to bypass the compiler driver and pass option directly through to the preprocessor. - Warning Options -
-fsyntax-only
: Check the code for syntax errors, but don't do anything beyond that.
# gcc stdc.c -E -### : llvm-gcc 调用 clang -cc1 预处理
$ gcc stdc.c -E -v
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdio.h
# g++ stdcpp.cpp -E -### : llvm-g++ 也是调用 clang -cc1 预处理
$ g++ stdcpp.cpp -E -v
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1/iostream
# gcc stdc.c -E -### : 调用 /usr/lib/gcc/aarch64-linux-gnu/11/cc1 -E 预处理
$ gcc stdc.c -E -v
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/gcc/aarch64-linux-gnu/11/include
/usr/local/include
/usr/include/aarch64-linux-gnu
/usr/include
End of search list.
/usr/include/stdio.h
COMPILER_PATH=/usr/lib/gcc/aarch64-linux-gnu/11/:/usr/lib/gcc/aarch64-linux-gnu/11/:/usr/lib/gcc/aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/11/:/usr/lib/gcc/aarch64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/aarch64-linux-gnu/11/:/usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/11/../../../../lib/:/lib/aarch64-linux-gnu/:/lib/../lib/:/usr/lib/aarch64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/aarch64-linux-gnu/11/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-E' '-v' '-mlittle-endian' '-mabi=lp64'
# g++ stdcpp.cpp -E -### : 调用 /usr/lib/gcc/aarch64-linux-gnu/11/cc1plus -E 预处理
$ g++ stdcpp.cpp -E -v
/usr/include/c++/11/iostream
COMPILER_PATH=/usr/lib/gcc/aarch64-linux-gnu/11/:/usr/lib/gcc/aarch64-linux-gnu/11/:/usr/lib/gcc/aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/11/:/usr/lib/gcc/aarch64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/aarch64-linux-gnu/11/:/usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu/:/usr/lib/gcc/aarch64-linux-gnu/11/../../../../lib/:/lib/aarch64-linux-gnu/:/lib/../lib/:/usr/lib/aarch64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/aarch64-linux-gnu/11/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-E' '-v' '-shared-libgcc' '-mlittle-endian' '-mabi=lp64'
VC2015 的头文件 INCLUDE 路径为:
- C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include
- C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt
Library Search Paths#
执行 clang -Xlinker -v
指定链接选项,不指定链接目标,则只显示 configured to support archs 信息:
- Options for Linking -
-Xlinker option
: Pass option as an option to the linker.
$ clang -Xlinker -v
@(#)PROGRAM:ld PROJECT:ld-1053.12
BUILD 15:45:29 Feb 3 2024
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em
will use ld-classic for: armv6 armv7 armv7s arm64_32 i386 armv6m armv7k armv7m armv7em
LTO support using: LLVM version 15.0.0 (static support for 29, runtime is 29)
TAPI support using: Apple TAPI version 15.0.0 (tapi-1500.3.2.2)
也可执行 clang -print-targets
查看 Registered Targets,参考 How to list supported target architectures in clang?。
指定链接空文件 /dev/null,可以查看 Library/Framework search paths,直接报错:
$ clang -Xlinker -v /dev/null
@(#)PROGRAM:ld PROJECT:ld-1053.12
BUILD 15:45:29 Feb 3 2024
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em
will use ld-classic for: armv6 armv7 armv7s arm64_32 i386 armv6m armv7k armv7m armv7em
LTO support using: LLVM version 15.0.0 (static support for 29, runtime is 29)
TAPI support using: Apple TAPI version 15.0.0 (tapi-1500.3.2.2)
Library search paths:
/usr/local/lib
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/swift
Framework search paths:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks
clang: error: unable to execute command: Segmentation fault: 11
clang: error: linker command failed due to signal (use -v to see invocation)
macOS 编译链接 C/C++
macOS 上编译链接 C 代码:dry-run: gcc stdc.c -###
;compile: gcc stdc.c -o c.out -v
。
macOS 上编译链接 C++ 代码:dry-run: g++ stdcpp.cpp -###
;compile: g++ stdcpp.cpp -o cpp.out -v
。
- gcc/g++ 都只调用了
clang cc1
和ld
两步命令。 - gcc std.c 链接
libLTO.dylib
、-lSystem
和libclang_rt.osx.a
;g++ stdcpp.cpp 在 -lSystem 前面插增链接选项-lc++
。 - 执行
otool -L c.out
/otool -L cpp.out
可查看依赖的动态库(dylib)。
Ubuntu 下执行 gcc/g++ 命令,调用 collect2 和 ld 链接,最终报错:
$ gcc -Xlinker -v /dev/null
collect2 version 11.4.0
/usr/bin/ld -plugin /usr/lib/gcc/aarch64-linux-gnu/11/liblto_plugin.so -plugin-opt=/usr/lib/gcc/aarch64-linux-gnu/11/lto-wrapper -plugin-opt=-fresolution=/tmp/cc2Mlb39.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr --hash-style=gnu --as-needed -dynamic-linker /lib/ld-linux-aarch64.so.1 -X -EL -maarch64linux --fix-cortex-a53-843419 -pie -z now -z relro /usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu/Scrt1.o /usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu/crti.o /usr/lib/gcc/aarch64-linux-gnu/11/crtbeginS.o -L/usr/lib/gcc/aarch64-linux-gnu/11 -L/usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu -L/usr/lib/gcc/aarch64-linux-gnu/11/../../../../lib -L/lib/aarch64-linux-gnu -L/lib/../lib -L/usr/lib/aarch64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/aarch64-linux-gnu/11/../../.. -v -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/aarch64-linux-gnu/11/crtendS.o /usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu/crtn.o
GNU ld (GNU Binutils for Ubuntu) 2.38
/usr/bin/ld: /usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x1c): undefined reference to `main'
/usr/bin/ld: (.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
$ g++ -x c++ -Xlinker -v /dev/null
collect2 version 11.4.0
/usr/bin/ld -plugin /usr/lib/gcc/aarch64-linux-gnu/11/liblto_plugin.so -plugin-opt=/usr/lib/gcc/aarch64-linux-gnu/11/lto-wrapper -plugin-opt=-fresolution=/tmp/ccx8f9Ks.res -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc --build-id --eh-frame-hdr --hash-style=gnu --as-needed -dynamic-linker /lib/ld-linux-aarch64.so.1 -X -EL -maarch64linux --fix-cortex-a53-843419 -pie -z now -z relro /usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu/Scrt1.o /usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu/crti.o /usr/lib/gcc/aarch64-linux-gnu/11/crtbeginS.o -L/usr/lib/gcc/aarch64-linux-gnu/11 -L/usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu -L/usr/lib/gcc/aarch64-linux-gnu/11/../../../../lib -L/lib/aarch64-linux-gnu -L/lib/../lib -L/usr/lib/aarch64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/aarch64-linux-gnu/11/../../.. -v /tmp/ccqgv1oL.o -lstdc++ -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/aarch64-linux-gnu/11/crtendS.o /usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu/crtn.o
GNU ld (GNU Binutils for Ubuntu) 2.38
/usr/bin/ld: /usr/lib/gcc/aarch64-linux-gnu/11/../../../aarch64-linux-gnu/Scrt1.o: in function `_start':
(.text+0x1c): undefined reference to `main'
/usr/bin/ld: (.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
Ubuntu 编译链接 C/C++
ubuntu 上编译链接 C 代码:dry-run: gcc stdc.c -###
;compile: gcc stdc.c -o c.out -v
。
- gcc 依次调用 cc1->as->collect2,链接 Scrt1.o,crti.o,crtbeginS.o,
-lc
([g]libc),crtendS.o,crtn.o。
ubuntu 上编译链接 C++ 代码:dry-run: g++ stdcpp.cpp -###
;compile: g++ stdcpp.cpp -o cpp.out -v
。
- g++ 依次调用 cc1plus->as->collect2,链接 Scrt1.o,crti.o,crtbeginS.o,
-lstdc++
(libstdc++),crtendS.o,crtn.o。
说明:
- gcc 的
cc1
已经集成了 cpp 预处理。 - collect2 内部调用 real
ld
完成最终的链接工作。 - 关于 crt(C Runtime),参考 crtbegin.o vs. crtbeginS.o,Mini FAQ about the misc libc/gcc crt files. 和 ELF Format Cheatsheet | Sections, Common objects and functions。
VC2015 的库文件 LIB 路径为:
- C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\lib
- C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10150.0\ucrt\x86
Library Dependencies#
执行 gcc/g++ 编译链接时,可指定 -###
dry-run,查看完整编译链接流程:
- gcc stdc.c -###
- g++ stdcpp.cpp -###
ABI Policy and Guidelines - Checking Active
- elf - Determine direct shared object dependencies of a Linux binary? - Stack Overflow
- windows - Discovery of Dynamic library dependency on Mac OS & Linux - Stack Overflow
- How to find out the dynamic libraries executables loads when run? - Unix & Linux Stack Exchange
ldd#
ldd
- print shared object dependencies.
ldd 打印依赖的动态共享库:libc.so.6, libstdc++.so.6。
rpi4b-ubuntu $ ldd cpp.out
linux-vdso.so.1 (0x0000ffff968c5000)
libstdc++.so.6 => /lib/aarch64-linux-gnu/libstdc++.so.6 (0x0000ffff96640000)
libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ffff96490000)
libm.so.6 => /lib/aarch64-linux-gnu/libm.so.6 (0x0000ffff963f0000)
/lib/ld-linux-aarch64.so.1 (0x0000ffff9688c000)
libgcc_s.so.1 => /lib/aarch64-linux-gnu/libgcc_s.so.1 (0x0000ffff963c0000)
macOS 与 Linux 上的 ldd 对应的命令是 otool -L
:
mbpa2991 $ otool -L c.out
c.out:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1345.100.2)
mbpa2991 $ otool -L cpp.out
cpp.out:
/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1700.255.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1345.100.2)
但 /usr/lib 下并没有找到这两个 dylib,参考:
- Why are my system libraries and frameworks not visible in macOS Monterey?
- Missing librairies in /usr/lib on Big Sur?: Since Big Sur, it somehow all became virtual.
在 macOS 上的 Library search paths 中过滤 libSystem 和 libc++,只搜到了 libSystem.B.tbd 和 libc++.1.tbd 及一堆软链替身(如 libc.tbd、libc++.tbd):
$ ls -l /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib | grep -E "lib(System|c\+\+)"
-rw-r--r-- 1 root wheel 309826 Nov 17 2021 libSystem.B.tbd
lrwxr-xr-x 1 root wheel 15 Oct 7 2021 libSystem.tbd -> libSystem.B.tbd
-rw-r--r-- 1 root wheel 145622 Nov 13 2021 libc++.1.tbd
lrwxr-xr-x 1 root wheel 12 Oct 7 2021 libc++.tbd -> libc++.1.tbd
-rw-r--r-- 1 root wheel 10571 Nov 13 2021 libc++abi.tbd
lrwxr-xr-x 1 root wheel 13 Oct 7 2021 libc.tbd -> libSystem.tbd
lrwxr-xr-x 1 root wheel 13 Oct 7 2021 libdl.tbd -> libSystem.tbd
lrwxr-xr-x 1 root wheel 13 Oct 7 2021 libgcc_s.1.tbd -> libSystem.tbd
lrwxr-xr-x 1 root wheel 13 Oct 7 2021 libm.tbd -> libSystem.tbd
lrwxr-xr-x 1 root wheel 13 Oct 7 2021 libpoll.tbd -> libSystem.tbd
lrwxr-xr-x 1 root wheel 13 Oct 7 2021 libproc.tbd -> libSystem.tbd
lrwxr-xr-x 1 root wheel 13 Oct 7 2021 libpthread.tbd -> libSystem.tbd
查看 libSystem.B.tbd 可知,libSystem 不提供任何符号和代码,它链接了 /usr/lib/system 中的许多其他 dylib,并将它们的符号作为自己的符号重新导出(reexported-libraries)。
$ tree /usr/lib/system
/usr/lib/system
├── introspection
│ ├── libdispatch.dylib
│ └── libsystem_pthread.dylib
├── libsystem_kernel.dylib
├── libsystem_platform.dylib
├── libsystem_pthread.dylib
└── wordexp-helper
2 directories, 6 files
tdb vs. dylib
关于 tdb 和 dylib 的关系,参考:
*.dylib
is the compiled binary that contains the machine code.
TDB
is the acronym for "Text Based Dylib stubs".
*.tbd
is a smaller text file, similar to a cross-platform module map.
ldconfig#
ldconfig
- configure dynamic linker run-time bindings.
-p
/ --print-cache: Print the lists of directories and candidate libraries stored in the current cache.
ldconfig -p 打印缓存中的动态共享库 libc.so.6, libstdc++.so.6。
objdump#
-f#
执行 file
命令查看 libc.so 文件属性(determine file type):
$ file /lib/aarch64-linux-gnu/libc.so.6
/lib/aarch64-linux-gnu/libc.so.6: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-aarch64.so.1, BuildID[sha1]=9e27cf97f03940293c6df3b107674ceda9c825d8, for GNU/Linux 3.7.0, stripped
执行 file
命令查看 libstdc++.so 文件属性:
$ file /lib/aarch64-linux-gnu/libstdc++.so.6
/lib/aarch64-linux-gnu/libstdc++.so.6: symbolic link to libstdc++.so.6.0.30
$ file /lib/aarch64-linux-gnu/libstdc++.so.6.0.30
/lib/aarch64-linux-gnu/libstdc++.so.6.0.30: ELF 64-bit LSB shared object, ARM aarch64, version 1 (GNU/Linux), dynamically linked, BuildID[sha1]=a012b2bb77110e84b266cd7425b50e57427abb02, stripped
objdump -a
查看 archive header;objdump -f
查看 file header。
-a
, --archive-headers Display archive header information-f
, --file-headers Display the contents of the overall file header
objdump -f /lib/aarch64-linux-gnu/libc.so.6
/lib/aarch64-linux-gnu/libc.so.6: file format elf64-littleaarch64
architecture: aarch64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x00000000000275e0
objdump -f /lib/aarch64-linux-gnu/libstdc++.so.6
/lib/aarch64-linux-gnu/libstdc++.so.6: file format elf64-littleaarch64
architecture: aarch64, flags 0x00000150:
HAS_SYMS, DYNAMIC, D_PAGED
start address 0x0000000000000000
-x#
objdump -x
(--all-headers): Display all available header information, including the symbol table and relocation entries.
- Dynamic Section: 中的 NEEDED 为依赖的(动态)库:libc.so.6, libstdc++.so.6。
- Version References: 中的 required 为依赖的(动态)库:GLIBC_2.17/GLIBC_2.34,GLIBCXX_3.4。
- 依赖的符号后面也有 @GLIBC_2.17/@GLIBC_2.34,@GLIBCXX_3.4 标记。
rpi4b-ubuntu $ objdump -x c.out
Dynamic Section:
NEEDED libc.so.6
Version References:
required from libc.so.6:
0x06969197 0x00 03 GLIBC_2.17
0x069691b4 0x00 02 GLIBC_2.34
SYMBOL TABLE:
0000000000000000 F *UND* 0000000000000000 __libc_start_main@GLIBC_2.34
0000000000000000 F *UND* 0000000000000000 printf@GLIBC_2.17
rpi4b-ubuntu $ objdump -x cpp.out
Dynamic Section:
NEEDED libstdc++.so.6
NEEDED libc.so.6
Version References:
required from libc.so.6:
0x069691b4 0x00 04 GLIBC_2.34
0x06969197 0x00 03 GLIBC_2.17
required from libstdc++.so.6:
0x08922974 0x00 02 GLIBCXX_3.4
SYMBOL TABLE:
0000000000000000 O *UND* 0000000000000000 _ZSt4cout@GLIBCXX_3.4
readelf#
readelf -h
: Display the ELF file header.
readelf -l
(--program-headers, --segments): Display the program headers
readelf -S
(--section-headers, --sections): Display the sections' header
readelf -e
(--headers): Equivalent to: -h -l -S
readelf -s
(--syms): Display the symbol table.
readelf -d
(--dynamic): Displays the contents of the file's dynamic section, if it has one.
readelf -a
(--all): Displays the complete structure of an object file.
其中 NEEDED 标记表示依赖(动态)库:libc.so.6, libstdc++.so.6。
nm#
nm
- list symbols from object files.
依赖的符号后面也有 @GLIBC_2.17/@GLIBC_2.34,@GLIBCXX_3.4 标记。
rpi4b-ubuntu $ nm cpp.out
0000000000000a10 t _Z41__static_initialization_and_destruction_0ii
U _ZNSolsEl@GLIBCXX_3.4
U _ZNSolsEPFRSoS_E@GLIBCXX_3.4
U _ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4
U _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4
U _ZSt4cout@GLIBCXX_3.4
U _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_@GLIBCXX_3.4
man nm 查看 nm(1) - Linux manual page,其中有关于 symbol type 的详细说明。