本文只列出glibc的makefile中比较难以找出的一些规则,一些细节可以详细阅读glibc的makefile系统。
I.编译
[redhat@localhost build]$ ../glibc-2.16.0/configure --disable-sanity-checks [redhat@localhost build]$ make | tee make.log
i.默认规则:
Makefile
30 all: lib others
ii.lib规则:
[redhat@localhost glibc-2.16.0]$ grep -n "^include" Makefile 25:include Makeconfig 78:include Makerules [redhat@localhost glibc-2.16.0]$ grep -n "lib:" Makeconfig Makerules Makefile Makerules:703:lib: lib-noranlib $(foreach l,$(libtypes),$(patsubst %,$(common-objpfx)$l,c)) Makerules:704:lib-noranlib: libobjs Makerules:718:subdir_lib: $(foreach o,$(object-suffixes-for-libc),$(objpfx)stamp$o) Makerules:829:install-lib.so := $(filter %.so,$(install-lib:%_pic.a=%.so)) Makerules:1134:cpp-srcs-left = $(all-nonlib:=.c) $(all-nonlib:=.cc) Makefile:122:lib-noranlib: subdir_lib Makefile:126:lib: $(common-objpfx)libc.so Makefile:128:lib: $(common-objpfx)linkobj/libc.so
iii.libc.so
lib的一个重要前提是libc.so,libc.so生成的一过程大致如下:
a.递归子目录,对源文件进行编译
b.由子目录生成的object文件生成libc_pic.a
c.由libc_pic.a及其它object文件生成libc.so
II.递归子目录
i.递归规则
Makefile
51 # These are the targets that are made by making them in each subdirectory. 52 +subdir_targets := subdir_lib objects objs others subdir_mostlyclean \ 53 subdir_clean subdir_distclean subdir_realclean \ 54 tests xtests subdir_lint.out \ 55 subdir_update-abi subdir_check-abi \ 56 subdir_echo-headers \ 57 subdir_install \ 58 subdir_objs subdir_stubs subdir_testclean \ 59 $(addprefix install-, no-libc.a bin lib data headers others) 223 # For each target, make it depend on DIR/target for each subdirectory DIR. 224 $(+subdir_targets): %: $(addsuffix /%,$(subdirs)) 225 226 # Compute a list of all those targets. 227 all-subdirs-targets := $(foreach dir,$(subdirs),\ 228 $(addprefix $(dir)/,$(+subdir_targets))) 229 230 # The action for each of those is to cd into the directory and make the 231 # target there. 232 $(all-subdirs-targets): 233 $(MAKE) $(PARALLELMFLAGS) $(subdir-target-args) $(@F) 234 235 define subdir-target-args 236 subdir=$(@D)$(if $($(@D)-srcdir),\ 237 -C $($(@D)-srcdir) ..=`pwd`/,\ 238 -C $(@D) ..=../) 239 endef
由以上可以看出,subdir_lib规则就是递归子目录去执行make,由子目录下的Makefile负责子目录的编译。
ii.子目录
Makeconfig
769 -include $(common-objpfx)sysd-sorted 770 subdirs = $(sorted-subdirs) 921 # These are the subdirectories containing the library source. The order 922 # is more or less arbitrary. The sorting step will take care of the 923 # dependencies. 924 all-subdirs = csu assert ctype locale intl catgets math setjmp signal \ 925 stdlib stdio-common libio malloc string wcsmbs time dirent \ 926 grp pwd posix io termios resource misc socket sysvipc gmon \ 927 gnulib iconv iconvdata wctype manual shadow gshadow po argp \ 928 crypt nss localedata timezone rt conform debug \ 929 $(add-on-subdirs) $(dlfcn) $(binfmt-subdir) 930 931 ifndef avoid-generated 932 all-Depend-files := $(wildcard $(foreach dir,$(all-subdirs),\ 933 $(firstword $($(dir)-srcdir) \ 934 $(..)$(dir))/Depend)) 935 $(common-objpfx)sysd-sorted: $(..)scripts/gen-sorted.awk \ 936 $(common-objpfx)config.make $(..)Makeconfig \ 937 $(wildcard $(sysdirs:=/Subdirs)) \ 938 $(all-Depend-files) 939 $(AWK) -f $< \ 940 -v subdirs='$(all-subdirs)' \ 941 -v srcpfx='$(..)' \ 942 $(filter %/Subdirs %/Depend,$^) > $@-tmp 943 mv -f $@-tmp $@
iii.生成的子目录
[redhat@localhost build]$ cat sysd-sorted $(common-objpfx)sysd-sorted: $(wildcard $(..)resolv/Depend) $(common-objpfx)sysd-sorted: $(wildcard $(..)nis/Depend) $(common-objpfx)sysd-sorted: $(wildcard $(..)nscd/Depend) sorted-subdirs := csu iconv locale localedata iconvdata assert ctype intl catgets math setjmp signal stdlib stdio-common libio dlfcn malloc string wcsmbs timezone time dirent grp pwd posix io termios resource misc socket sysvipc gmon gnulib wctype manual shadow gshadow po argp crypt nptl resolv nss rt conform debug libidn nptl_db inet hesiod sunrpc nis nscd streams login elf sysd-sorted-done := t [redhat@localhost build]$
III.libc.so
i.libc.so规则:
Makerules
549 # Pre-link the objects of libc_pic.a so that we can locally resolve 550 # COMMON symbols before we link against ld.so. This is because ld.so 551 # contains some of libc_pic.a already, which will prevent the COMMONs 552 # from being allocated in libc.so, which introduces evil dependencies 553 # between libc.so and ld.so, which can make it impossible to upgrade. 554 $(common-objpfx)libc_pic.os: $(common-objpfx)libc_pic.a 555 $(LINK.o) -nostdlib -nostartfiles -r -o $@ \ 556 $(LDFLAGS-c_pic.os) -Wl,-d $(whole-archive) $^ -o $@ 557 558 ifeq (,$(strip $(shlib-lds-flags))) 559 # Generate a list of -R options to excise .gnu.glibc-stub.* sections. 560 $(common-objpfx)libc_pic.opts: $(common-objpfx)libc_pic.os 561 $(OBJDUMP) -h $< | \ 562 $(AWK) '$$2 ~ /\.gnu\.glibc-stub\./ { print "-R", $$2 }' \ 563 > $@T 564 mv -f $@T $@ 565 # Apply those -R options. 566 $(common-objpfx)libc_pic.os.clean: $(common-objpfx)libc_pic.opts \ 567 $(common-objpfx)libc_pic.os 568 $(OBJCOPY) @$^ $@ 569 generated += libc_pic.opts libc_pic.os.clean 570 571 libc_pic_clean := .clean 572 endif 573 574 # Use our own special initializer and finalizer files for libc.so. 575 $(common-objpfx)libc.so: $(elfobjdir)/soinit.os \ 576 $(common-objpfx)libc_pic.os$(libc_pic_clean) \ 577 $(elfobjdir)/sofini.os \ 578 $(elfobjdir)/interp.os $(elfobjdir)/ld.so \ 577 $(elfobjdir)/sofini.os \ 578 $(elfobjdir)/interp.os $(elfobjdir)/ld.so \ 579 $(shlib-lds) 580 $(build-shlib) 581 ifeq ($(versioning),yes) 582 $(common-objpfx)libc.so: $(common-objpfx)libc.map 583 endif 584 common-generated += libc.so libc_pic.os 585 ifdef libc.so-version 586 $(common-objpfx)libc.so$(libc.so-version): $(common-objpfx)libc.so 587 $(make-link) 588 common-generated += libc.so$(libc.so-version) 589 endif 590 endif
ii.libc_pic.a规则
1.libtype
Makeconfig:
687 # Enable object files for different versions of the library. 688 # Various things use $(object-suffixes) to know what all to make. 689 # The compilation rules use $(CPPFLAGS-${SUFFIX}) and $(CFLAGS-${SUFFIX}) 690 # to pass different flags for each flavor. 691 libtypes = $(foreach o,$(object-suffixes-for-libc),$(libtype$o)) 692 all-object-suffixes := .o .os .op .og .ob .oS 693 object-suffixes := 694 CPPFLAGS-.o = $(pic-default) 695 CFLAGS-.o = $(filter %frame-pointer,$(+cflags)) 696 libtype.o := lib%.a 697 object-suffixes += .o 698 ifeq (yes,$(build-shared)) 699 # Under --enable-shared, we will build a shared library of PIC objects. 700 # The PIC object files are named foo.os. 701 object-suffixes += .os 702 CPPFLAGS-.os = -DPIC -DSHARED 703 CFLAGS-.os = $(filter %frame-pointer,$(+cflags)) $(pic-ccflag) 704 libtype.os := lib%_pic.a
2.libc_pic.a规则
Makerules:
742 # Now define explicit rules to build the library archives; these depend 743 # on the stamp files built above. 744 define o-iterator-doit 745 $(common-objpfx)$(patsubst %,$(libtype$o),c): \ 746 $(subdirs-stamp-o) $(common-objpfx)stamp$o; $$(do-makelib) 747 endef 748 define do-makelib 749 cd $(common-objdir) && \ 750 $(AR) $(CREATE_ARFLAGS) $(@F) `cat $(patsubst $(common-objpfx)%,%,$^)` 751 endef 752 subdirs-stamps := $(foreach d,$(subdirs),$(common-objpfx)$d/stamp%) 753 subdirs-stamp-o = $(subst %,$o,$(subdirs-stamps)) 754 ifndef subdir 755 $(subdirs-stamps): subdir_lib; 756 endif 757 object-suffixes-left = $(object-suffixes-for-libc) 758 include $(o-iterator)
libc_pic.a的生成就是从子目录的stamp.os文件中取出object文件名称,然后用ar归档为libc_pic.a
3.libc_pic.a生成
[redhat@localhost build]$ grep -n "libc_pic.a" make.log 7390:cd /home/redhat/src/build && ar cruv libc_pic.a `cat csu/stamp.os iconv/stamp.os locale/stamp.os localedata/stamp.os iconvdata/stamp.os assert/stamp.os ctype/stamp.os intl/stamp.os catgets/stamp.os math/stamp.os setjmp/stamp.os signal/stamp.os stdlib/stamp.os stdio-common/stamp.os libio/stamp.os dlfcn/stamp.os malloc/stamp.os string/stamp.os wcsmbs/stamp.os timezone/stamp.os time/stamp.os dirent/stamp.os grp/stamp.os pwd/stamp.os posix/stamp.os io/stamp.os termios/stamp.os resource/stamp.os misc/stamp.os socket/stamp.os sysvipc/stamp.os gmon/stamp.os gnulib/stamp.os wctype/stamp.os manual/stamp.os shadow/stamp.os gshadow/stamp.os po/stamp.os argp/stamp.os crypt/stamp.os nptl/stamp.os resolv/stamp.os nss/stamp.os rt/stamp.os conform/stamp.os debug/stamp.os libidn/stamp.os nptl_db/stamp.os inet/stamp.os hesiod/stamp.os sunrpc/stamp.os nis/stamp.os nscd/stamp.os streams/stamp.os login/stamp.os elf/stamp.os stamp.os` [redhat@localhost build]$ cat malloc/stamp.os malloc/malloc.os malloc/morecore.os malloc/mcheck.os malloc/mtrace.os malloc/obstack.os malloc/set-freeres.os malloc/thread-freeres.os [redhat@localhost build]$
iii.优先选择系统相关的实现
glibc提供的api,有一些是系统相关的调用;而系统调用一般与平台相关,不同的平台有不同的实现。
glibc的做法是平台无关目录下提供一个默认的实现,返回ENOSYS;在具体的平台目录下再有一个真正的实现。
以fork为例:
[redhat@localhost glibc-2.16.0]$ find . -name "fork.c" ./sysdeps/mach/hurd/fork.c ./posix/fork.c ./nptl/sysdeps/unix/sysv/linux/x86_64/fork.c ./nptl/sysdeps/unix/sysv/linux/powerpc/fork.c ./nptl/sysdeps/unix/sysv/linux/sh/fork.c ./nptl/sysdeps/unix/sysv/linux/s390/fork.c ./nptl/sysdeps/unix/sysv/linux/fork.c ./nptl/sysdeps/unix/sysv/linux/sparc/fork.c ./nptl/sysdeps/unix/sysv/linux/i386/fork.c [redhat@localhost glibc-2.16.0]$ sed -n 25,+9p posix/fork.c int __fork () { __set_errno (ENOSYS); return -1; } libc_hidden_def (__fork) stub_warning (fork) weak_alias (__fork, fork) [redhat@localhost glibc-2.16.0]$
优先选择系统相关目录的规则如下:
[redhat@localhost glibc-2.16.0]$ sed -n 229,+55p Makerules -include $(common-objpfx)sysd-rules ifneq ($(sysd-rules-sysdirs),$(config-sysdirs)) # The value of $(+sysdep_dirs) the sysd-rules was computed for # differs from the one we are using now. So force a rebuild of sysd-rules. sysd-rules-force = FORCE FORCE: endif $(common-objpfx)sysd-rules: $(common-objpfx)config.make $(..)Makerules \ $(sysdep-makefiles) $(sysdep-makeconfigs) \ $(sysd-rules-force) -@rm -f $@T (echo 'sysd-rules-sysdirs := $(config-sysdirs)'; \ for dir in $(config-sysdirs); do \ case "$$dir" in \ /*) ;; \ *) dir="\$$(..)$$dir" ;; \ esac; \ asm='.S'; \ $(check-inhibit-asm) \ for o in $(all-object-suffixes); do \ set $(subst :, ,$(sysd-rules-patterns)); \ while [ $$# -ge 2 ]; do \ t=$$1; shift; \ d=$$1; shift; \ v=$${t%%%}; [ x"$$v" = x ] || v="\$$($${v}CPPFLAGS)"; \ for s in $$asm .c; do \ echo "\$$(objpfx)$$t$$o: $$dir/$$d$$s \$$(before-compile)"; \ echo " \$$(compile-command$$s) $$v"; \ done; \ done; \ done; \ echo "\$$(inst_includedir)/%.h: $$dir/%.h \$$(+force)"; \ echo " \$$(do-install)"; \ done; \ echo 'sysd-rules-done = t') > $@T mv -f $@T $@ ifndef sysd-rules-done # Don't do deps until this exists, because it provides rules to make the deps. no_deps=t endif define o-iterator-doit $(objpfx)%$o: %.S $(before-compile); $$(compile-command.S) endef object-suffixes-left := $(all-object-suffixes) include $(o-iterator) define o-iterator-doit $(objpfx)%$o: %.c $(before-compile); $$(compile-command.c) endef object-suffixes-left := $(all-object-suffixes) include $(o-iterator) define o-iterator-doit $(objpfx)%$o: %.cc $(before-compile); $$(compile-command.cc) [redhat@localhost glibc-2.16.0]$
生成sysd-rules文件内容为:
[redhat@localhost build]$ head -n 7 sysd-rules sysd-rules-sysdirs := sysdeps/unix/sysv/linux/x86_64/64/nptl sysdeps/unix/sysv/linux/x86_64/64 nptl/sysdeps/unix/sysv/linux/x86_64 nptl/sysdeps/unix/sysv/linux/x86 sysdeps/unix/sysv/linux/x86 sysdeps/unix/sysv/linux/x86_64 sysdeps/unix/sysv/linux/wordsize-64 nptl/sysdeps/unix/sysv/linux nptl/sysdeps/pthread sysdeps/pthread sysdeps/unix/sysv/linux sysdeps/gnu sysdeps/unix/inet nptl/sysdeps/unix/sysv sysdeps/unix/sysv sysdeps/unix/x86_64 nptl/sysdeps/unix sysdeps/unix sysdeps/posix nptl/sysdeps/x86_64/64 sysdeps/x86_64/64 sysdeps/x86_64/fpu/multiarch sysdeps/x86_64/fpu sysdeps/x86/fpu sysdeps/x86_64/multiarch nptl/sysdeps/x86_64 sysdeps/x86_64 sysdeps/x86 sysdeps/ieee754/ldbl-96 sysdeps/ieee754/dbl-64/wordsize-64 sysdeps/ieee754/dbl-64 sysdeps/ieee754/flt-32 sysdeps/wordsize-64 sysdeps/ieee754 sysdeps/generic $(objpfx)%.o: $(..)sysdeps/unix/sysv/linux/x86_64/64/nptl/%.S $(before-compile) $(compile-command.S) $(objpfx)%.o: $(..)sysdeps/unix/sysv/linux/x86_64/64/nptl/%.c $(before-compile) $(compile-command.c) $(objpfx)rtld-%.o: $(..)sysdeps/unix/sysv/linux/x86_64/64/nptl/rtld-%.S $(before-compile) $(compile-command.S) $(rtld-CPPFLAGS) [redhat@localhost build]$ tail -n 5 sysd-rules $(objpfx)ptw-%.oS: $(..)sysdeps/generic/%.c $(before-compile) $(compile-command.c) $(ptw-CPPFLAGS) $(inst_includedir)/%.h: $(..)sysdeps/generic/%.h $(+force) $(do-install) sysd-rules-done = t [redhat@localhost build]$
可以看出生成.o文件优先选择系统相关目录下的实现,如果没有才会选择当前目录下的实现。