在修改一个Makefile时遇到了这个问题。 具体的情况为:
目录结构,其中liba1.c和liba1b.c都是含义一个函数的源文件,里面只有一个接口,显示内容为printf而已。
[zhang@zwfedora23 lib1]$ ls liba1b.c liba1b.h liba1.c liba1.h Makefile LIBA1_SRC:=$(wildcard *.c) LIBA1_OBJ:=$(LIBA1_SRC:%.c=%.o) LIBA1_STATIC:=liba1.a CC=gcc AR=ar .PHONY: all clean all: $(LIBA1_OBJ) $(LIBA1_STATIC) $(LIBA1_OBJ):$(LIBA1_SRC) $(CC) -c $^ -o $@ $(LIBA1_STATIC):$(LIBA1_OBJ) $(AR) -rcv $@ $^ clean: @rm -f $(LIBA1_STATIC) @rm -f $(LIBA1_OBJ)执行make的结果:
[zhang@zwfedora23 lib1]$ make gcc -c liba1.c liba1b.c -o liba1.o gcc: fatal error: cannot specify -o with -c, -S or -E with multiple files compilation terminated. Makefile:15: recipe for target 'liba1.o' failed make: *** [liba1.o] Error 1 [zhang@zwfedora23 lib1]$首先看到了那一句, cannot specify -o with -c ,-S or -E with multiple files.然后我就把目录中的liba1b.c和对应的liba1b.h修改了文件名后缀,为的是此目录只含有一个.c文件。
[zhang@zwfedora23 lib1]$ ls liba1.a liba1b-c liba1b-h liba1.c liba1.h liba1.o Makefile [zhang@zwfedora23 lib1]$此时在执行make,即可以成功的生成.a文件,且这个.a文件中只包含一个.c文件。
[zhang@zwfedora23 lib1]$ make gcc -c liba1.c -o liba1.o ar -rcv liba1.a liba1.o a - liba1.o [zhang@zwfedora23 lib1]$ ls liba1.a liba1b-c liba1b-h liba1.c liba1.h liba1.o Makefile [zhang@zwfedora23 lib1]$难道gcc -c 这样的参数不适合多个源文件使用? 那如果这个.a文件需要多个.c文件生成怎么办?这个问题好像太蠢了,因为我之前已经编译了无数个库了,现在才来问这个问题,可见当时使用makefile也是稀里糊涂的使用,根本没有研究明白,现在好了,全都需要花时间补上。 去网上查了一下,当需要有多个源文件生成一个.a文件时采用的方法是把每个源文件生成的自己对应的.o文件,然后再把多个.o文件使用ar组合为一个整体的.a文件。
废话不说了,赶快想解决办法。 我现在需要做的就是把每个c源文件都生成一个o文件,然后把这些个object文件私用ar组织起来形成一个真正的a文件。 为了实现这样的目的,我又去搜了一下《跟我一起写Makefile》这篇文档,当时刚学makefile时也是看的它,但是没有完全看进去,现在需要从里面找一些能够实现上面的目标的操作,这个文档都看完看懂需要至少2个小时,没办法,从头开始来吧。不过好在刚看到静态模式,就感觉好像就可以解决我目前的问题了。我把我当前的目录结构贴出来看看,基本跟上面的一样,这是文件名换了。
[zhang@zwfedora23 libs]$ ls libs1.c libs1.h libs2.c libs2.h main.c Makefile [zhang@zwfedora23 libs]$ SRC:=$(wildcard *.c) #OBJS:=$(wildcard *.o) OBJS := $(patsubst %.c,%.o,$(wildcard *.c)) LIB_A := libs.a CC:=gcc CFLAGS:= -I./ .PNONY:all clean all: $(LIB_A) clean: @rm -f $(OBJS) @rm -f $(LIB_A) #$(OBJS):$(SRC) # $(CC) -o $@ $^ $(OBJS):%.o:%.c $(CC) -c $(CFLAGS) $< -o $@ $(LIB_A):$(OBJS) $(AR) rcv $@ $^ @echo '$$@' = $@ @echo '$$^' = $^ @echo SRC=$(SRC) @echo OBJS=$(OBJS) #$(CC) -o $(LIB_A) $(OBJS)执行结果:
[zhang@zwfedora23 libs]$ make gcc -c -I./ libs1.c -o libs1.o gcc -c -I./ libs2.c -o libs2.o gcc -c -I./ main.c -o main.o ar rcv libs.a libs1.o libs2.o main.o a - libs1.o a - libs2.o a - main.o $@ = libs.a $^ = libs1.o libs2.o main.o SRC=libs1.c libs2.c main.c OBJS=libs1.o libs2.o main.o #gcc -o libs.a libs1.o libs2.o main.o [zhang@zwfedora23 libs]$ ls libs1.c libs1.h libs1.o libs2.c libs2.h libs2.o libs.a main.c main.o Makefile [zhang@zwfedora23 libs]$这时已经生成了盼望的.o文件和.a文件,为了验证一下这个.a文件是否正确,我又写了一个简单的main.c,然后编译:
[zhang@zwfedora23 libs]$ gcc main.c -ls -L./ -o test [zhang@zwfedora23 libs]$ ./test hello hello,libs2可以看到test的输出是正确的,至此我的问题也解决了。
最后再总结一下之前没有成功的原因。 主要是没有给出生成.o文件的生成规则,只给出了
OBJS:=$(wildcard %.o)这个表达式,当时以为OBJS就是包含*.o的变量了。实际上,OBJS的值确实是libs1.o libs2.o,但是问题是我没有给出怎么生成这两个object文件的规则,然后就认为执行完它就已经有object文件了,这样的想法简直太错误了。静下心来,认真的读了《跟我一起写Makefile》才认识到自己的愚蠢思维,漏洞太多。
