本文只列出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文件优先选择系统相关目录下的实现,如果没有才会选择当前目录下的实现。