目录下有test1.cpp, test2.cpp, test3.cpp三个独立文件(彼此之间并无依赖与调用关系), 要编译成三个可执行程序, 怎么搞呢? 我们看看makefile:


[plain] view plain​ copy


  1. test1: test1.cpp
  2. test2: test2.cpp
  3. test3: test3.cpp
  4. clean:
  5. rm -f test1 test2 test3


编译一下:



[plain] view plain​ copy


  1. taoge@localhost Desktop> make
  2. g++ test1.cpp -o test1
  3. taoge@localhost Desktop>


可见, 只编译了test1.cpp, 没有达到效果。 为什么呢? 因为执行make命令时, 认为第一个test1是最终的目标文件, 且三个cpp文件确实相互独立, 所以不会触发test2和test3对应执行。



那改一下:


[plain] view plain​ copy


  1. test1 test2 test3: test1.cpp test2.cpp test3.cpp
  2. clean:
  3. rm -f test1 test2 test3


结果:



[plain] view plain​ copy


  1. taoge@localhost Desktop> make
  2. g++ test1.cpp test2.cpp test3.cpp -o test1
  3. /tmp/ccAX6NNB.o: In function `main':
  4. test2.cpp:(.text+0x72): multiple definition of `main'
  5. /tmp/ccaITY1Z.o:test1.cpp:(.text+0x72): first defined here
  6. /tmp/cc4Wsk9m.o: In function `main':
  7. test3.cpp:(.text+0x72): multiple definition of `main'
  8. /tmp/ccaITY1Z.o:test1.cpp:(.text+0x72): first defined here
  9. collect2: ld returned 1 exit status
  10. make: *** [test1] Error 1
  11. taoge@localhost Desktop>


显然不行啊, 怎么能对三个独立的cpp文件进行杂糅链接呢?



那怎么办? 我们反思一下上面的两次失败:

在前一次中, 我们其实只定义了一个target文件(因cpp独立), 也就是test1.

在后一次中, 我们定义了三个target文件, 可是, 杂糅链接了(依赖关系杂糅)。


那好, 我们来改进一下, 兼顾到上面两种情况:


[plain] view plain​ copy


  1. all: test1 test2 test3
  2. test1: test1.cpp
  3. test2: test2.cpp
  4. test3: test3.cpp
  5. clean:
  6. rm -f test1 test2 test3


执行一下(如下用make命令也可以):



[plain] view plain​ copy


  1. taoge@localhost Desktop> make clean
  2. rm -f test1 test2 test3
  3. taoge@localhost Desktop> make all
  4. g++ test1.cpp -o test1
  5. g++ test2.cpp -o test2
  6. g++ test3.cpp -o test3
  7. taoge@localhost Desktop> ls
  8. makefile test1 test1.cpp test2 test2.cpp test3 test3.cpp
  9. taoge@localhost Desktop>


        我们思考一下, 为什么这样可以?  make命令首先找到all标志, 发现了必须要生成test1, test2, test3, 于是就往下找, 去生成他们, 于是就达到了我们的目标。


这里有个疑问, 为什么没有生成all文件呢? 因为all下面并没有待执行的命令,也无法自动推导。 我们来看看改动的makefile:


[plain] view plain​ copy


  1. all: test1 test2 test3
  2. @echo testing
  3. test1: test1.cpp
  4. test2: test2.cpp
  5. test3: test3.cpp
  6. clean:
  7. rm -f test1 test2 test3


结果为(如下用make命令也可以):



[plain] view plain​ copy


  1. taoge@localhost Desktop> make all
  2. g++ test1.cpp -o test1
  3. g++ test2.cpp -o test2
  4. g++ test3.cpp -o test3
  5. testing
  6. taoge@localhost Desktop>


可见, 如果all后有命令, 也会被执行哈。



以上部分应该比较好动, 现在还有个问题, 如果有100个cpp文件, 那该怎么搞起呢? 写到test100? 麻烦死了, 明显不符合计算机的思维, 好, 那就搞个模式规则吧, 如下:


[plain] view plain​ copy


  1. all: test1 test2 test3
  2. %:%.cpp
  3. g++ $< -o $@
  4. clean:
  5. rm -f test1 test2 test3


结果(如下用make命令也可以):



[plain] view plain​ copy


  1. taoge@localhost Desktop> make clean
  2. rm -f test1 test2 test3
  3. taoge@localhost Desktop> make all
  4. g++ test1.cpp -o test1
  5. g++ test2.cpp -o test2
  6. g++ test3.cpp -o test3
  7. taoge@localhost Desktop>


%是通配的,看看如下这两句:



[plain] view plain​ copy


  1. %:%.cpp
  2. g++ $< -o $@


意思是把所有的cpp文件, 都编译成对应的最终文件。 无需都解释了吧(当然, 你得了解$<和$@)。



其实, 如上程序还没有解决根本问题, 继续优化吧:


[plain] view plain​ copy


  1. CPPLIST = $(wildcard *.cpp) # get cpp file list
  2. TARGET = $(patsubst %.cpp, %, $(CPPLIST)) # get corresponding target file

  3. all: $(TARGET)
  4. @echo ------------------
  5. @echo log1: $(TARGET)
  6. @echo log2: $(CPPLIST)

  7. %:%.cpp
  8. g++ $< -o $@

  9. clean:
  10. rm -f $(TARGET)


看下结果(如下用make命令也可以):



[plain] view plain​ copy


  1. taoge@localhost Desktop> make clean
  2. rm -f test1 test2 test3
  3. taoge@localhost Desktop> make all
  4. g++ test1.cpp -o test1
  5. g++ test2.cpp -o test2
  6. g++ test3.cpp -o test3
  7. ------------------------
  8. log1: test1 test2 test3
  9. log2: test1.cpp test2.cpp test3.cpp
  10. taoge@localhost Desktop>


搞定。



本文所谓的模式规则, 其实就是:


[plain] view plain​ copy


  1. %:%.cpp
  2. g++ $< -o $@


其实, 这个还是很好理解的。


最后想说一下, 有点循环的感觉啊!