在修改一个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》才认识到自己的愚蠢思维,漏洞太多。