Makefile 生成文件追踪
14 Jun 2017很多大型开源项目使用 make 来构建, 有时候我们想知道一个文件是怎么被构建出来的, 或者说是从哪些文件构建出来的, 知道这些对于找到程序的入口是很有帮助的. 那么该怎么做呢?
第一反应肯定是直接看 Makefile, 但是大型项目的 Makefile 都很复杂, 各种 include
和变量.
虽然 make 提供 -n
和 -p
选项, 但是因为构建命令里还会调用 make
命令,
当使用 -n
选项时, 这些命令并不会执行, 所以看不到最终执行的所有指令.
那么该怎么办呢? 其实很简单, 直接构建然后从构建输出的日志里来寻找答案,
因为 make 默认会将构建时执行的命令打印出来 (如果使用了 -s
选项或者命令加了 @
前缀就不会输出).
下面我们以查看 OpenJDK 中 bin/java
是如何构建出来的为例来看下具体的操作:
-
首先将项目完整的构建一遍
-
将你想要追踪的文件删除, 这里我们将
bin/java
删掉 -
重新构建一遍项目同时将输出重定向到一个文件里
步骤 1 和 2 主要是为了减少构建日志输出的量从而方便搜索
-
最后就是从输出日志里搜索相关的信息
以 bin/java
为例, 我们在构建日志里搜索 bin/java
, 找到如下日志:
/Applications/Xcode.app/Contents/Developer/usr/bin/llvm-gcc -o /Users/yoncise/Downloads/openjdk/build/macosx-x86_64/bin/java -m64 -Xlinker -rpath -Xlinker @loader_path/. -Xlinker -install_name -Xlinker @rpath/java -L/Users/yoncise/Downloads/openjdk/build/macosx-x86_64/lib -Wl,-all_load /Users/yoncise/Downloads/openjdk/build/macosx-x86_64/tmp/java/jli/obj64/static/libjli.a -framework Cocoa -framework Security -framework ApplicationServices -sectcreate __TEXT __info_plist ../../../../src/macosx/lib/Info-cmdline.plist \
/Users/yoncise/Downloads/openjdk/build/macosx-x86_64/tmp/java/java/obj64/main.o -pthread -lz -pthread
我们可以发现 bin/java
的构建依赖 /Users/yoncise/Downloads/openjdk/build/macosx-x86_64/tmp/java/java/obj64/main.o
.
根据目录我们可以知道, 这个文件是第一次完整构建的时候生成的并不是程序的源码, 删掉它, 再重复上面的步骤构建一遍.
再一次构建完成后, 我们在构建日志里搜索 obj64/main.o
可以找到如下日志:
/Applications/Xcode.app/Contents/Developer/usr/bin/llvm-gcc -Os -fno-strict-aliasing -fPIC -W -Wall -Wno-unused -Wno-parentheses -pipe -m64 -fno-omit-frame-pointer -D_LITTLE_ENDIAN -F/System/Library/Frameworks/JavaVM.framework/Frameworks -F/System/Library/Frameworks/ApplicationServices.framework/Frameworks -I/usr/X11R6/include -D_DARWIN_UNLIMITED_SELECT -DNDEBUG -DARCH='"x86_64"' -Dx86_64 -D_ALLBSD_SOURCE -DRELEASE='"1.7.0-internal"' -DFULL_VERSION='"1.7.0-internal-yoncise_2017_06_13_23_02-b00"' -DJDK_MAJOR_VERSION='"1"' -DJDK_MINOR_VERSION='"7"' -D_LARGEFILE64_SOURCE -D_GNU_SOURCE -D_REENTRANT -DMACOSX -D_LP64=1 -I/usr/X11R6/include -D_DARWIN_UNLIMITED_SELECT -I. -I/Users/yoncise/Downloads/openjdk/build/macosx-x86_64/tmp/java/java/CClassHeaders -I../../../../src/macosx/javavm/export -I../../../../src/share/javavm/export -I../../../../src/share/bin -I../../../../src/macosx/bin -I../../../../src/solaris/bin -DPACKAGE_PATH='"/opt/local"' -DPROGNAME='"java"' -DEXPAND_CLASSPATH_WILDCARDS -DLAUNCHER_NAME='"openjdk"' -c -o /Users/yoncise/Downloads/openjdk/build/macosx-x86_64/tmp/java/java/obj64/main.o \
-DRELEASE='"1.7.0-internal"' -DFULL_VERSION='"1.7.0-internal-yoncise_2017_06_13_23_02-b00"' -DJDK_MAJOR_VERSION='"1"' -DJDK_MINOR_VERSION='"7"' ../../../../src/share/bin/main.c
至此, 我们发现 bin/java
的入口文件是 src/share/bin/main.c
!