zoukankan      html  css  js  c++  java
  • GNU make使用(一)

    [时间:2017-01] [状态:Self]
    [关键词:makefile,gcc,编译,动态库,静态库,可执行文件,shell命令]

    引言

    前段时间在Linux下编写一个可测试的程序发现,我对makefile实践太少各种别扭吧。因此参考网上的一篇文章,自己尝试下常用的可执行文件、静态库、动态库的自动编译,以及调用,作为后续开发的参考。
    本文主要包括三部分:

    • 可执行文件的Makefile
    • 静态库*.a的Makefile
    • 动态库*.b的Makefile

    这是我对Makefile学习总结的第二篇文章,其他的可参考GNU make简介

    本文主要参考,感谢@竹林听雨的分享。
    在Linux下编译时常用的命令有:

    • make : 编译整个工程
    • make install : 输出编译之后的结果,可能是系统目录,也可能是自定义目录
    • make clean : 清除编译过程中的中间文件,比如.o,.s等
    • make distclean : 恢复编译前的环境,注意本文中使用make veryclean

    1. 可执行文件的Makefile

    代码如下:

    #源文件,自动找所有.c和.cpp文件,并将目标定义为同名.o文件
    SOURCE  := $(wildcard *.c) $(wildcard *.cpp)
    OBJS    := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE)))
    
    #目标文件名,输入任意你想要的执行文件名
    TARGET  := exe_check
    
    #编译参数
    CC      := g++
    LIBS    :=
    LDFLAGS :=
    DEFINES :=
    INCLUDE := -I.
    CFLAGS  := -g -Wall -O3 $(DEFINES) $(INCLUDE)
    CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H
    
    #下面的基本上不需要做任何改动了
    .PHONY : everything objs clean veryclean rebuild
    
    everything : $(TARGET)
    
    all : $(TARGET)
    
    objs : $(OBJS)
    
    rebuild: veryclean everything
    
    clean :
    	rm -fr *.so
    	rm -fr *.o
    
    veryclean : clean
    	rm -fr $(TARGET)
    #这里是实际完成编译的命令
    $(TARGET) : $(OBJS)
    	$(CC) $(CXXFLAGS) -o $@ $(OBJS) $(LDFLAGS) $(LIBS)
    

    如果你是直接拷贝这个makefile的话,麻烦检查下上面的shell命令前空白必须是Tab键,不能是空格。

    2. 静态库的Makefile和调用示例

    Makefile文件如下,主要使用ar/ranlib打包命令:

    #共享库文件名,lib*.a
    TARGET  := libtest.a
    
    #编译参数
    CC      := g++
    AR      = ar
    RANLIB  = ranlib
    LIBS    :=
    LDFLAGS :=
    DEFINES :=
    INCLUDE := -I.
    CFLAGS  := -g -Wall -O3 $(DEFINES) $(INCLUDE)
    CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H
    
    #下面的基本上不需要做任何改动了
    
    #源文件,自动找所有.c和.cpp文件,并将目标定义为同名.o文件
    SOURCE  := $(wildcard *.c) $(wildcard *.cpp)
    OBJS    := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE)))
    #头文件,自动查找.h文件
    HEADER := $(wildcard *.h)
    
    .PHONY : everything objs clean veryclean rebuild install
    
    everything : $(TARGET)
    
    all : $(TARGET)
    
    objs : $(OBJS)
    
    rebuild: veryclean everything
                 
    clean :
    	rm -fr *.o
    
    veryclean : clean
    	rm -fr $(TARGET)
    
    install :
    	test -f ./sample/lib && echo ' ' || mkdir ./sample/lib
    	cp $(TARGET) ./sample/lib/
    	test -f ./sample/include/ && echo ' ' || mkdir ./sample/include
    	cp $(HEADER) ./sample/include/
    
    $(TARGET) : $(OBJS)
    	$(AR) cru $(TARGET) $(OBJS)
    	$(RANLIB) $(TARGET)
    

    由于一般动态库或者静态库需要安装,这里添见了install标签。

    调用静态库的话,需要使用下面makefile,这里仅给出相对可执行文件的makefile差别,如下:

    #compile and lib parameter
    #编译参数
    CC      := g++
    LIBS    := -ltest
    LDFLAGS := -L./lib/
    DEFINES :=
    INCLUDE := -I. -I./include
    CFLAGS  := -g -Wall -O3 $(DEFINES) $(INCLUDE)
    CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H
    

    主要加入了静态库所在的目录及-l命令。

    3. 动态库的Makefile及调用示例

    Makefile如下,直接调用g++编译成动态库:

    #共享库文件名,lib*.so
    TARGET  := libtest.so
    
    #编译参数
    CC      := g++
    LIBS    :=
    LDFLAGS :=
    DEFINES :=
    INCLUDE := -I.
    CFLAGS  := -g -Wall -O3 $(DEFINES) $(INCLUDE)
    CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H
    SHARE   := -fpic -shared -o
      
    
    #下面的基本上不需要做任何改动了
    
    #源文件,自动找所有.c和.cpp文件,并将目标定义为同名.o文件
    SOURCE  := $(wildcard *.c) $(wildcard *.cpp)
    OBJS    := $(patsubst %.c,%.o,$(patsubst %.cpp,%.o,$(SOURCE)))
    #头文件,自动查找.h文件
    HEADER := $(wildcard *.h)
    
    .PHONY : everything objs clean veryclean rebuild install
    
    everything : $(TARGET)
    
    all : $(TARGET)
    
    objs : $(OBJS)
    	$(CC) -c -fPIC $(SOURCE)
    
    rebuild: veryclean everything
             
    clean :
    	rm -fr *.o
        
    veryclean : clean
    	rm -fr $(TARGET)
    
    install :
    	test -d ./sample/lib && echo ' ' || mkdir ./sample/lib
    	cp $(TARGET) ./sample/lib/
    	test -d ./sample/include/ && echo ' ' || mkdir ./sample/include
    	cp $(HEADER) ./sample/include/
    
    $(TARGET) : objs
    	$(CC) $(CXXFLAGS) $(SHARE) $@ $(OBJS) $(LDFLAGS) $(LIBS)
    

    这里就是需要关注下-fPIC-fpic的不同使用位置,否则可能会出现编译错误。
    调用动态库的示例代码的Makefile跟可执行文件的主要区别如下:

    #目标文件名,输入任意你想要的执行文件名
    TARGET  := shared_check
    
    #编译参数
    CC      := g++
    LIBS    := -ltest
    LDFLAGS := -L./lib/
    DEFINES :=
    INCLUDE := -I. -I./include
    CFLAGS  := -g -Wall -O3 $(DEFINES) $(INCLUDE)
    CXXFLAGS:= $(CFLAGS) -DHAVE_CONFIG_H
    

    4. 小结

    简单整理完了,直接看Makefile确实不是很难,但是其中涉及比较多的shell命令,比如wild、test、patsubst以及gcc编译指令,这方面有待加强。
    不做实际验证才不会明白其中有各种坑的。简单过一遍GNU Makefile还是很有帮助的。

    本文所有涉及的Makefile及源码可以从我的git下载,url:https://git.oschina.net/Tocy/SampleCode.git。相关文件位于makefile-template文件夹下。

  • 相关阅读:
    在firefox里面查看AMF信息
    addFrameScript 修改自定义button 名字
    [转]游戏UI与flash 组件开发
    as 运算符 与 where T : class
    Process.Start传参
    站长工具
    SaveFileDialog使用方法
    iis admin service 无法设置 因为不是服务器?
    将文件夹层次显示在treeview控件中
    磁盘fat32转NTFS
  • 原文地址:https://www.cnblogs.com/tocy/p/makefile-reference-1.html
Copyright © 2011-2022 走看看