glibc 知:构建机制

1. 前言

文本结合glibc-2.34的构建过程,解读其Makefile是如何工作的。

参考“glibc 知:构建2.34版本”的构建方法:

mkdir -p glibc-2.34/build
cd glibc-2.34/build
/xxxx/glibc-2.34/configure --prefix=/usr
make -j8 2>&1 | tee ../build.log

作者水平有限,只能渐进明细,本文会不断更新迭代。

1.1. 执行配置命令

执行configure之后,构建目录下生成如下一些文件:

[maminjie@fedora build]$ /mnt/hgfs/projects/opensrc/glibc/glibc-2.34/configure --prefix=/usr
[maminjie@fedora build]$ ls
bits  config.h  config.log  config.make  config.status  Makefile

在当前目录下,直接执行make命令就可以进行构建glibc了。不过,这里我们先不构建,先来看一下配置生成的Makefile内容:

srcdir = /mnt/hgfs/projects/opensrc/glibc/glibc-2.34

# Uncomment the line below if you want to do parallel build.
# PARALLELMFLAGS = -j 4

.PHONY: all install bench

all .DEFAULT:
    $(MAKE) -r PARALLELMFLAGS="$(PARALLELMFLAGS)" -C $(srcdir) objdir=`pwd` $@

install:
    LC_ALL=C; export LC_ALL; \
    $(MAKE) -r PARALLELMFLAGS="$(PARALLELMFLAGS)" -C $(srcdir) objdir=`pwd` $@

bench bench-clean bench-build:
    $(MAKE) -C $(srcdir)/benchtests $(PARALLELMFLAGS) objdir=`pwd` $@

# Convenience target to rebuild ULPs for all math tests.
regen-ulps:
    $(MAKE) -C $(srcdir)/math $(PARALLELMFLAGS) objdir=`pwd` $@

该Makefile内容很简单,终极目标all的执行命令是到glibc的源码目录下执行真正的Makefile。

1.2. 生成构建日志

执行make生成构建日志,如下所示:

$ make -j8 2>&1 | tee ../build.log
$ ls
abi-versions.h            jmp_buf-ssp.h          linkobj                  soversions.mk
argp                      jmp_buf-ssp.h.d        locale                   stamp.o
assert                    ldbl-compat-choose.h   localedata               stamp.os
bits                      ld.map                 locale-defines.h         stamp.oS
catgets                   libanl.map             locale-defines.h.d       stdio-common
config.h                  libBrokenLocale.map    login                    stdlib
config.log                libc.a                 Makefile                 string
config.make               libc-abis.h            malloc                   sunrpc
config.status             libc-abis.stamp        manual                   support
conform                   libc_malloc_debug.map  math                     sysd-rules
cpu-features-offsets.h    libc.map               mathvec                  sysd-sorted
cpu-features-offsets.h.d  libc-modules.h         misc                     sysd-syscalls
crypt                     libc-modules.stmp      nis                      sysd-versions
csu                       libc_nonshared.a       nptl                     sysvipc
ctype                     libc_pic.a             nptl_db                  tcb-offsets.h
debug                     libc_pic.opts          nscd                     tcb-offsets.h.d
debugglibc.sh             libc_pic.os            nss                      termios
dirent                    libc_pic.os.clean      po                       testrun.sh
dlfcn                     libcrypt.map           posix                    time
dl-tunable-list.h         libc.so                pthread-pi-defines.h     time64-compat.mk
dl-tunable-list.stmp      libc.so.6              pthread-pi-defines.h.d   time64-compat.mk.i
dummy.c                   libdl.map              pwd                      timezone
dummy.o                   libio                  resolv                   tlsdesc.h
dummy.o.dt                libm.map               resource                 tlsdesc.h.d
elf                       libmvec.map            rt                       ucontext_i.h
first-versions.h          libnsl.map             rtld-offsets.h           ucontext_i.h.d
format.lds                libnss_compat.map      rtld-offsets.h.d         unwindbuf.h
gmon                      libnss_db.map          runtime-linker.h         unwindbuf.h.d
gnu                       libnss_dns.map         runtime-linker.stamp     Versions.all
gnulib                    libnss_files.map       setjmp                   Versions.def
grp                       libnss_hesiod.map      shadow                   Versions.mk
gshadow                   libpthread.map         shlib-versions.v         versions.stmp
hesiod                    libresolv.map          shlib-versions.v.i       Versions.tmp
iconv                     librt.map              sigaltstack-offsets.h    Versions.v
iconvdata                 libthread_db.map       sigaltstack-offsets.h.d  Versions.v.i
inet                      libutil.map            signal                   wcsmbs
intl                      link-defines.h         socket                   wctype
io                        link-defines.h.d       soversions.i

build.log日志文件的前面内容如下所示:

ake -r PARALLELMFLAGS="" -C /mnt/hgfs/projects/opensrc/glibc/glibc-2.34 objdir=`pwd` all
make[1]: Entering directory '/mnt/hgfs/projects/opensrc/glibc/glibc-2.34'
LC_ALL=C gawk -f scripts/sysd-rules.awk > /home/maminjie/glibc-2.34/build/sysd-rulesT \
        -v all_object_suffixes='.o .os .oS' \
        -v inhibit_sysdep_asm='' \
        -v sysd_rules_patterns='%:% rtld-%:rtld-% rtld-%:% m_%:s_%' \
        -v config_sysdirs='sysdeps/unix/sysv/linux/x86_64/64 sysdeps/unix/sysv/linux/x86_64 sysdeps/unix/sysv/linux/x86 sysdeps/x86/nptl sysdeps/unix/sysv/linux/wordsize-64 sysdeps/x86_64/nptl sysdeps/unix/sysv/linux sysdeps/nptl sysdeps/pthread sysdeps/gnu sysdeps/unix/inet sysdeps/unix/sysv sysdeps/unix/x86_64 sysdeps/unix sysdeps/posix sysdeps/x86_64/64 sysdeps/x86_64/fpu/multiarch sysdeps/x86_64/fpu sysdeps/x86/fpu sysdeps/x86_64/multiarch sysdeps/x86_64 sysdeps/x86 sysdeps/ieee754/float128 sysdeps/ieee754/ldbl-96 sysdeps/ieee754/dbl-64 sysdeps/ieee754/flt-32 sysdeps/wordsize-64 sysdeps/ieee754 sysdeps/generic'
mv -f /home/maminjie/glibc-2.34/build/sysd-rulesT /home/maminjie/glibc-2.34/build/sysd-rules
gawk -f scripts/gen-sorted.awk \
       -v subdirs='csu assert ctype locale intl catgets math setjmp signal stdlib stdio-common libio malloc string wcsmbs time dirent grp pwd posix io termios resource misc socket sysvipc gmon gnulib iconv iconvdata wctype manual shadow gshadow po argp localedata timezone rt conform debug mathvec support dlfcn elf crypt' \
       -v srcpfx='' \
       sysdeps/nptl/Subdirs sysdeps/un
...

2. 构建

2.1. 总体机制

下面将通过分析glibc源码目录下的顶层Makefile,Makeconfig,Makerules,Rules等来解读glibc的构建机制。

2.1.1. 默认规则

$ grep -n "^include" Makefile
25:include Makeconfig
89:include Makerules

$ grep -nw "all:" Makeconfig Makerules Makefile
Makeconfig:26:all: # Make this the default goal
Makeconfig:1237:$(common-objpfx)Versions.all: $(..)scripts/firstversions.awk \
Makefile:30:all: minihelp lib others

2.1.2. lib规则

$ grep -nw "lib:" Makeconfig Makerules Makefile
Makerules:835:lib: lib-noranlib $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c))
Makerules:981:install-lib.so := $(filter %.so,$(install-lib:%_pic.a=%.so))
Makefile:131:lib: $(common-objpfx)libc.so $(common-objpfx)linkobj/libc.so

$ grep -nw "lib-noranlib:" Makeconfig Makerules Makefile
Makerules:836:lib-noranlib: libobjs
Makefile:127:lib-noranlib: subdir_lib

$ grep -nw "libobjs:" Makeconfig Makerules Makefile
Makerules:896:libobjs: $(foreach o,$(object-suffixes-for-libc),$(objpfx)stamp$o)

目标lib的依赖分别是:stamp$o,subdir_lib,libtypes,libc.so几个。

2.1.3. stamp规则

stamp%o是glibc中间目标文件的时间戳文件

$ grep -n stamp Makeconfig Makerules Makefile
Makerules:294:# We use a stamp file to avoid unnecessary recompilations.
Makerules:849:# Create the stamp$o files to keep the parent makefile happy.
Makerules:850:subdir_lib: $(foreach o,$(object-suffixes-for-libc),$(objpfx)stamp$o)
Makerules:851:$(foreach o,$(object-suffixes-for-libc),$(objpfx)stamp$o):
Makerules:856:# Define explicit rules to update each $(objpfx)stamp.SUFFIX
Makerules:857:# timestamp file; these rules (one explicit rule is generated for each
Makerules:858:# object suffix) write a list of objects to update in the stamp file.
Makerules:862:$(objpfx)stamp$o: $(o-objects); $$(do-stamp)
Makerules:864:define do-stamp
Makerules:875:# on the stamp files built above.
Makerules:878:          $(subdirs-stamp-o) $(common-objpfx)stamp$o; $$(do-makelib)
Makerules:884:subdirs-stamps := $(foreach d,$(subdirs),$(common-objpfx)$d/stamp%)
Makerules:885:subdirs-stamp-o = $(subst %,$o,$(subdirs-stamps))
Makerules:887:$(subdirs-stamps): subdir_lib;
Makerules:896:libobjs: $(foreach o,$(object-suffixes-for-libc),$(objpfx)stamp$o)
Makerules:1464:-rm -f $(objpfx)stamp$o $(o-objects))

Makerules文件中关于stamp内容如下:

# For object-suffix $o, the list of objects with that suffix.
# Makefiles can define `elide-routines.so = foo' to leave foo.so out.
o-objects = $(patsubst %.o,%$o,$(filter-out $(patsubst %,$(objpfx)%.o,\
						       $(elide-routines$o)),\
					    $(objects))) \
	    $(addprefix $(objpfx),$(o-objects$o))

others: $(addprefix $(objpfx),$(install-lib))

ifndef objects

# Create the stamp$o files to keep the parent makefile happy.
subdir_lib: $(foreach o,$(object-suffixes-for-libc),$(objpfx)stamp$o)
$(foreach o,$(object-suffixes-for-libc),$(objpfx)stamp$o):
	$(make-target-directory)
	rm -f $@; > $@
else

# Define explicit rules to update each $(objpfx)stamp.SUFFIX
# timestamp file; these rules (one explicit rule is generated for each
# object suffix) write a list of objects to update in the stamp file.
# The parent will then actually add them all to the archive in the
# archive rule, below.
define o-iterator-doit
$(objpfx)stamp$o: $(o-objects); $$(do-stamp)
endef
define do-stamp
$(make-target-directory)
echo '$(patsubst $(objpfx)%,$(addsuffix /,$(subdir))%,$^)' > $@T
mv -f $@T $@
endef
object-suffixes-left := $(object-suffixes-for-libc)
include $(o-iterator)

endif

根据构建过程,结合构建规则,实际glibc各子目录下生成的stamp%o文件内容为各子目录编译的中间o文件列表。

以csu子目录为例:

[maminjie@fedora csu]$ ls
abi-note.o       dso_handle.o.dt   gmon-start.os.dt  Mcrt1.o             sysdep.o
abi-note.o.dt    dso_handle.os     init-first.o      Scrt1.o             sysdep.o.dt
abi-tag.h        dso_handle.os.dt  init-first.o.dt   stamp.o             sysdep.os
check_fds.o      errno-loc.o       init-first.os     stamp.os            sysdep.os.dt
check_fds.o.dt   errno-loc.o.dt    init-first.os.dt  stamp.oS            unwind-resume.os
check_fds.os     errno-loc.os      init.o            start.o             unwind-resume.os.dt
check_fds.os.dt  errno-loc.os.dt   init.o.dt         start.o.dt          version.o
crt1.o           errno.o           libc-start.o      start.os            version.o.dt
crti.o           errno.o.dt        libc-start.o.dt   start.os.dt         version.os
crti.o.dt        errno.os          libc-start.os     static-reloc.o      version.os.dt
crtn.o           errno.os.dt       libc-start.os.dt  static-reloc.o.dt
crtn.o.dt        gcrt1.o           libc-tls.o        static-reloc.os
dso_handle.o     gmon-start.os     libc-tls.o.dt     static-reloc.os.dt
[maminjie@fedora csu]$ cat stamp.o
csu/init-first.o csu/libc-start.o csu/sysdep.o csu/version.o csu/check_fds.o csu/libc-tls.o csu/dso_handle.o csu/errno.o csu/errno-loc.o
[maminjie@fedora csu]$ cat stamp.os
csu/init-first.os csu/libc-start.os csu/sysdep.os csu/version.os csu/check_fds.os csu/dso_handle.os csu/unwind-resume.os csu/errno.os csu/errno-loc.os

2.1.4. subdir_lib规则

$ grep -nw "subdir_lib" Makeconfig Makerules Makefile
Makerules:850:subdir_lib: $(foreach o,$(object-suffixes-for-libc),$(objpfx)stamp$o)
Makerules:887:$(subdirs-stamps): subdir_lib;
Makefile:61:+subdir_targets     := subdir_lib objects objs others subdir_mostlyclean    \
Makefile:127:lib-noranlib: subdir_lib

Makefile文件中关于subdir_lib的主要内容如下:

# These are the targets that are made by making them in each subdirectory.
+subdir_targets	:= subdir_lib objects objs others subdir_mostlyclean	\
		   subdir_clean subdir_distclean subdir_realclean	\
		   tests xtests						\
		   subdir_update-abi subdir_check-abi			\
		   subdir_update-all-abi				\
		   subdir_echo-headers					\
		   subdir_install					\
		   subdir_objs subdir_stubs subdir_testclean		\
		   $(addprefix install-, no-libc.a bin lib data headers others)

...
# For each target, make it depend on DIR/target for each subdirectory DIR.
$(+subdir_targets): %: $(addsuffix /%,$(subdirs))

# Compute a list of all those targets.
all-subdirs-targets := $(foreach dir,$(subdirs),\
				 $(addprefix $(dir)/,$(+subdir_targets)))

# The action for each of those is to cd into the directory and make the
# target there.
$(all-subdirs-targets):
	$(MAKE) $(PARALLELMFLAGS) $(subdir-target-args) $(@F)

define subdir-target-args
subdir=$(@D)$(if $($(@D)-srcdir),\
-C $($(@D)-srcdir) ..=`pwd`/,\
-C $(@D) ..=../)
endef

subdir_lib目标实际上是递归glibc的源码子目录,编译每个子目录的subdir_lib目标,其它子目录目标类比,简单的解析如下:

subdirs := csu iconv locale ...
subdir_lib: csu/subdir_lib iconv/subdir_lib locale/subdir_lib
all-subdirs-targets := csu/subdir_lib csu/objects ... iconv/subdir_lib iconv/objects ..
csu/subdir_lib:
   $(MAKE) $(PARALLELMFLAGS) $(subdir-target-args) subdir_lib
iconv/subdir_lib:
   $(MAKE) $(PARALLELMFLAGS) $(subdir-target-args) subdir_lib
2.1.4.1. subdirs列表

subdirs的内容如下所示:

$ grep -nw "subdirs" Makeconfig Makerules Makefile
Makeconfig:1103:subdirs = $(sorted-subdirs)

$ grep -rn sorted-subdirs
build/sysd-sorted:6:sorted-subdirs := csu iconv locale localedata iconvdata assert ctype intl catgets math setjmp signal stdlib stdio-common libio dlfcn nptl rt malloc string wcsmbs timezone time dirent grp pwd posix io termios resource misc socket sysvipc gmon gnulib wctype manual shadow gshadow po argp conform debug mathvec support crypt nptl_db inet resolv nss hesiod sunrpc nis nscd login elf

$ $ grep -n sysd-sorted Makeconfig Makerules Makefile
Makeconfig:1102:-include $(common-objpfx)sysd-sorted
...
Makeconfig:1342:$(common-objpfx)sysd-sorted: $(..)scripts/gen-sorted.awk \
Makefile:507:       $(addprefix $(objpfx),sysd-sorted soversions.mk soversions.i)

Makeconfig文件中生成sysd-sorted文件的主要内容如下:

# This is a partial list of subdirectories containing the library source.
# The order is more or less arbitrary.  The sorting step will take care of the
# dependencies and generate sorted-subdirs dynamically.
all-subdirs = csu assert ctype locale intl catgets math setjmp signal	    \
	      stdlib stdio-common libio malloc string wcsmbs time dirent    \
	      grp pwd posix io termios resource misc socket sysvipc gmon    \
	      gnulib iconv iconvdata wctype manual shadow gshadow po argp   \
	      localedata timezone rt conform debug mathvec support	    \
	      dlfcn elf

ifeq ($(build-crypt),yes)
all-subdirs += crypt
rpath-dirs += crypt
endif

ifndef avoid-generated
# sysd-sorted itself will contain rules making the sysd-sorted target
# depend on Depend files.  But if you just added a Depend file to an
# existing directory not in all-subdirs, then sysd-sorted needs to
# be regenerated, so it depends on existing $(sorted-subdirs:=/Depend) files.
all-Depend-files := $(wildcard $(sort \
			$(foreach dir,$(all-subdirs),\
				  $(firstword $($(dir)-srcdir) \
				  $(..)$(dir))/Depend) \
			$(sorted-subdirs:=/Depend)))
$(common-objpfx)sysd-sorted: $(..)scripts/gen-sorted.awk \
			     $(common-objpfx)config.make $(..)Makeconfig \
			     $(wildcard $(sysdirs:=/Subdirs)) \
			     $(all-Depend-files)
	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

canpool

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值