• 为工程增加条件编译开关


    在最近的项目中,要求把录制程序移植到嵌入式板卡上,原来的vlc模块无法被支持(板卡上无法安装vlc程序以及相应的库),因此要求编译一个去掉vlc模块的版本。折腾半天弄出来了,由于对makefile不熟,很多地方实现的不够理想,仅仅是能用而已。

    下面是步骤:

    (1)首先编译源代码

    在代码中增加编译开关(宏定义):MODULE_WITHOUT_VLC

    在源代码中所有涉及到vlc模块的 代码处使用该宏定义重写,确保如果定义了MODULE_WITHOUT_VLC,代码也能正常运行(只是不支持vlc模块而已)

     注意:宏MODULE_WITHOUT_VLC并不需要在源代码中定义,下面会做说明

    (2)编辑Makefile 

    由于去掉了vlc模块,所有使用到vlc模块的源文件都不需要编译, 我们将所有待编译的目标文件存放到变量$(ALL_OBJFILE)中,这样的话我们需要从中剔除不需要编译的目标文件:

    OBJ_COMP_NOVLC = $(filter-out $(OBJ_VLC), $(ALL_OBJFILE))

    这样, $(OBJ_COMP_NOVLC)中存放的就是去除vlc模块的所有需要编译的目标文件

    同时,在连接时去我们也需要去除vlc模块。

    由于在代码中需要条件编译开关,我把它放在Makefile中作为g++的参数传进来:

     $(CXX) --verbose -DMODULE_WITHOUT_VLC -c -o $@ $< $(INCPATHS) -g -Wall -rdynamic

    最后我们的Makefile如下:

     1 ##################################################################################
    2 #
    3 #编译Record工程
    4 #
    5 ##################################################################################
    6 #编译选项
    7 CXX = g++
    8 OPTI = -o3
    9 CXXFLAGS = -Wall -Wno-strict-aliasing -Wno-unused-variable
    10
    11 LIBPATH = /usr/local/lib
    12 LIBS = -lpthread -lhcnetsdk -llog4cpp
    13 EXE = Record
    14 EXE_novlc = Record.novlc
    15 DIST_PATH = http://www.cnblogs.com/Record/
    16
    17 #mysql模块
    18 LIB_MYSQL = -rdynamic -L/usr/lib/mysql -lmysqlclient_r -lz -lcrypt -lnsl -lm -lpthread
    19 LIBS += $(LIB_MYSQL)
    20
    21 #日志模块
    22
    23 #包含头文件路径
    24 SUBDIR = $(shell ls http://www.cnblogs.com/src -R | grep /)
    25 SUBDIRS = $(subst :,/,$(SUBDIR))
    26 INCPATHS = $(subst http://www.cnblogs.com/,-Ihttp://www.cnblogs.com/,$(SUBDIRS))
    27 INCPATHS += -I http://www.cnblogs.com/include/
    28
    29 VPATH = $(subst : ,:,$(SUBDIR))./
    30 SOURCE = $(foreach dir,$(SUBDIRS),$(wildcard $(dir)*.cpp))
    31
    32 #使用vlc模块的目标文件
    33 OBJ_VLC = CInputVideoVLC.o COutputVideoVLC.o
    34 LIB_VLC = -lvlc
    35
    36 #根据cpp文件名生成对应的目标文件名.o
    37 OBJS = $(patsubst %.cpp,%.o,$(SOURCE))
    38 #所有待编译的目标文件
    39 ALL_OBJFILE = $(foreach dir,$(OBJS),$(notdir $(dir)))
    40 OBJSPATH = $(addprefix obj/,$(OBJFILE))
    41 ALL_LIBS = $(LIBS)
    42 ALL_LIBS += $(LIB_VLC)
    43
    44 #without vlc support
    45 #最终编译时使用的目标文件
    46 OBJ_COMP_NOVLC = $(filter-out $(OBJ_VLC), $(ALL_OBJFILE))
    47 LIBS_COMP_NOVLC = $(LIBS)
    48
    49 $(EXE):$(ALL_OBJFILE)
    50 $(CXX) -L$(LIBPATH) -Wl,-rpath=/usr/local/lib/ -o $(EXE) $(ALL_OBJFILE) $(INCPATHS) $(ALL_LIBS)
    51 mv $(EXE) $(DIST_PATH)
    52
    53 $(ALL_OBJFILE):%.o:%.cpp
    54 $(CXX) --verbose -c -o $@ $< $(INCPATHS) -g -Wall -rdynamic
    55
    56
    57 novlc:$(EXE_novlc)
    58 @echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    59 @echo "NOTICE:compiled without vlv support."
    60 @echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    61
    62 $(EXE_novlc):$(OBJ_COMP_NOVLC)
    63 $(CXX) -L$(LIBPATH) -Wl,-rpath=/usr/local/lib/ -o $(EXE_novlc) $(OBJ_COMP_NOVLC) $(INCPATHS) $(LIBS_COMP_NOVLC)
    64 mv $(EXE_novlc) $(DIST_PATH)$(EXE)
    65
    66 $(OBJ_COMP_NOVLC):%.o:%.cpp
    67 $(CXX) --verbose -DMODULE_WITHOUT_VLC -c -o $@ $< $(INCPATHS) -g -Wall -rdynamic
    68
    69
    70 #依赖文件
    71 DPPS = $(patsubst %.cpp,%.dpp,$(SOURCE))
    72 include $(DPPS)
    73 %.dpp: %.cpp
    74 g++ $(INCPATHS) -MM $(CPPFLAGS) $< > $@.$$$$; \
    75 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
    76 rm -f $@.$$$$
    77
    78
    79 .PHONY:clean
    80 clean:
    81 rm -rf $(ALL_OBJFILE)
    82 rm -rf $(DPPS)
    83 rm -rf $(EXE) $(EXE_novlc)


     正常编译时直接make即可;

    不需要vlc模块,则执行 make novlc就搞定了,不需要做任何其他改动. 

    Updated:2012-01-05

    存在bug,直接make时将会出错,修改后如下: 

     1 ##################################################################################
    2 #
    3 #编译Record工程
    4 #
    5 ##################################################################################
    6 #编译目标
    7 #默认编译全部
    8 target =
    9
    10 #编译选项
    11 CXX = g++
    12 OPTI = -o3
    13 CXXFLAGS = -Wall -Wno-strict-aliasing -Wno-unused-variable -Wl,-rpath=/usr/local/lib/
    14
    15 LIBPATH = /usr/local/lib
    16 LIBS = -lpthread -lhcnetsdk -llog4cpp
    17 EXE = Record
    18 DIST_PATH = http://www.cnblogs.com/Record/
    19
    20 #mysql模块
    21 LIB_MYSQL = -rdynamic -L/usr/lib/mysql -lmysqlclient_r -lz -lcrypt -lnsl -lm -lpthread
    22 LIBS += $(LIB_MYSQL)
    23
    24 #日志模块
    25
    26 #包含头文件路径
    27 SUBDIR = $(shell ls http://www.cnblogs.com/src -R | grep /)
    28 SUBDIRS = $(subst :,/,$(SUBDIR))
    29 INCPATHS = $(subst http://www.cnblogs.com/,-Ihttp://www.cnblogs.com/,$(SUBDIRS))
    30 INCPATHS += -Ihttp://www.cnblogs.com/include/
    31
    32 VPATH = $(subst : ,:,$(SUBDIR))./
    33 SOURCE = $(foreach dir,$(SUBDIRS),$(wildcard $(dir)*.cpp))
    34
    35 #使用vlc模块的目标文件
    36 OBJ_VLC = CInputVideoVLC.o COutputVideoVLC.o
    37 LIB_VLC = -lvlc
    38
    39 #根据cpp文件名生成对应的目标文件名.o
    40 TMP_OBJS = $(patsubst %.cpp,%.o,$(SOURCE))
    41 #所有待编译的目标文件
    42 OBJFILE = $(foreach dir,$(TMP_OBJS),$(notdir $(dir)))
    43 OBJSPATH = $(addprefix obj/,$(OBJFILE))
    44
    45 #without vlc support
    46 ifeq ($(target), novlc)
    47 OBJS = $(filter-out $(OBJ_VLC), $(OBJFILE))
    48 CXXFLAGS += -DMODULE_WITHOUT_VLC
    49 else
    50 OBJS = $(OBJFILE)
    51 LIBS += $(LIB_VLC)
    52 endif
    53
    54 $(EXE):$(OBJS)
    55 $(CXX) -o $(EXE) $(CXXFLAGS) -L$(LIBPATH) $(INCPATHS) $(OBJS) $(LIBS)
    56 mv $(EXE) $(DIST_PATH)
    57
    58 $(OBJS):%.o:%.cpp
    59 $(CXX) -c $(CXXFLAGS) -o $@ $< $(INCPATHS) -g -Wall -rdynamic
    60
    61 #依赖文件
    62 DPPS = $(patsubst %.cpp,%.dpp,$(SOURCE))
    63 include $(DPPS)
    64 %.dpp: %.cpp
    65 g++ $(INCPATHS) -MM $(CPPFLAGS) $< > $@.$$$$; \
    66 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
    67 rm -f $@.$$$$
    68
    69
    70 .PHONY:clean
    71 clean:
    72 rm -rf $(OBJS)
    73 rm -rf $(DPPS)
    74 rm -rf $(EXE) $(EXE_novlc)

    一般情况直接make;

    去掉vlc模块时make target=novlc。
     

     Updated:2012-02-02

    去年的最后的一个工作日,将程序移植到了新借测的64位NAS上,有个小问题:录制的海康摄像头在linux下没有64位的sdk,该功能也就无法使用,需要把相应的模块给禁用掉。

    当时简单的做了一下处理,编了一个版本给测试的,让他们春节期间测试性能看看。

    今天上班,第一件事就是修改Makefile,使之支持多个编译开关--可以禁用更多的模块。经过一上午的折腾,终于弄好了:

      1 ##################################################################################
    2 #
    3 #预定义编译参数
    4 #
    5 ##################################################################################
    6 #编译目标
    7 #默认编译全部
    8 #支持vlc模块
    9 enable_vlc =
    10 #支持海康摄像头
    11 enable_hik =
    12
    13 #编译选项
    14 CXX = g++
    15 OPTI = -o3
    16 CXXFLAGS = -Wall -Wno-strict-aliasing -Wno-unused-variable -Wl,-rpath=/usr/local/lib/
    17
    18 #基础模块
    19 LIBPATH = /usr/local/lib
    20 LIBS = -lpthread -llog4cpp
    21 EXE = Record
    22 DIST_PATH = http://www.cnblogs.com/Record/
    23
    24 #mysql模块
    25 LIB_MYSQL = -rdynamic -L/usr/lib/mysql -lmysqlclient_r -lz -lcrypt -lnsl -lm -lpthread
    26 LIBS += $(LIB_MYSQL)
    27
    28 #VLC模块
    29 OBJ_VLC = CInputVideoVLC.o COutputVideoVLC.o VLC.o
    30 LIB_VLC = -lvlc
    31
    32 #海康模块
    33 OBJ_HIK = CInputVideoDriver.o COutputVideoDriverRcrd.o
    34 LIB_HIK = -lhcnetsdk
    35
    36
    37
    38 ##################################################################################
    39 #
    40 #处理编译参数
    41 #
    42 ##################################################################################
    43
    44 #包含头文件路径
    45 SUBDIR = $(shell ls http://www.cnblogs.com/src -R | grep /)
    46 SUBDIRS = $(subst :,/,$(SUBDIR))
    47 INCPATHS = $(subst http://www.cnblogs.com/,-Ihttp://www.cnblogs.com/,$(SUBDIRS))
    48 INCPATHS += -Ihttp://www.cnblogs.com/include/
    49
    50 VPATH = $(subst : ,:,$(SUBDIR))./
    51 SOURCE = $(foreach dir,$(SUBDIRS),$(wildcard $(dir)*.cpp))
    52
    53 #根据cpp文件名生成对应的目标文件名.o
    54 TMP_OBJS = $(patsubst %.cpp,%.o,$(SOURCE))
    55 #所有待编译的目标文件
    56 OBJFILE = $(foreach dir,$(TMP_OBJS),$(notdir $(dir)))
    57 OBJSPATH = $(addprefix obj/,$(OBJFILE))
    58
    59 #支持vlc模块
    60 ifeq ($(enable_vlc), no)
    61 OBJS = $(filter-out $(OBJ_VLC), $(OBJFILE))
    62 CXXFLAGS += -DMODULE_WITHOUT_VLC
    63 else
    64 OBJS = $(OBJFILE)
    65 LIBS += $(LIB_VLC)
    66 endif
    67 OBJFILE := $(OBJS)
    68
    69 #支持海康模块
    70 ifeq ($(enable_hik), no)
    71 OBJS = $(filter-out $(OBJ_HIK), $(OBJFILE))
    72 CXXFLAGS += -DMODULE_WITHOUT_HIK
    73 else
    74 LIBS += $(LIB_HIK)
    75 endif
    76 OBJFILE := $(OBJS)
    77
    78
    79
    80 ##################################################################################
    81 #
    82 #执行编译过程
    83 #
    84 ##################################################################################
    85
    86 $(EXE):$(OBJS)
    87 $(CXX) -o $(EXE) $(CXXFLAGS) -L$(LIBPATH) $(INCPATHS) $(OBJS) $(LIBS)
    88 mv $(EXE) $(DIST_PATH)
    89
    90 $(OBJS):%.o:%.cpp
    91 $(CXX) -c $(CXXFLAGS) -o $@ $< $(INCPATHS) -g -Wall -rdynamic
    92
    93 #依赖文件
    94 DPPS = $(patsubst %.cpp,%.dpp,$(SOURCE))
    95 include $(DPPS)
    96 %.dpp: %.cpp
    97 g++ $(INCPATHS) -MM $(CPPFLAGS) $< > $@.$$$$; \
    98 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
    99 rm -f $@.$$$$
    100
    101
    102 .PHONY:clean
    103 clean:
    104 rm -rf $(OBJS)
    105 rm -rf $(DPPS)
    106 rm -rf $(EXE) $(EXE_novlc)

    照上个版本做了不小改动,就不细说了。

    一般情况直接make;

    禁用vlc模块: make enable_vlc=no

    禁用海康模块: make enable_hik=no

    都禁用:make enable_vlc=no enable_hik=no

    以后如果需要禁用更多的模块,依次添加即可。 

    ps:在修改的时候, 遇到一个Makefile的语法问题。说明如下:

    OBJFILE = $(OBJS) 

    OBJS = $(filter-out $(OBJ_HIK), $(OBJFILE))

    在make时会报错:“递归变量,最终引用自己”,经查发现这是由于“递归展开式变量”给自己赋值是不支持的,而应该采用如下方式: 

    OBJFILE := $(OBJS)

    OBJS = $(filter-out $(OBJ_HIK), $(OBJFILE))

     6.2 两种变量定义(赋值)
    在GNU make中,变量的定义有两种方式(或者称为风格)。我们把使用这两种方式定义的变量可以看作变量的两种不同风格。变量的这两种不同的风格的区别在于:1. 定义方式;2. 展开时机。下边我们分别对这两种不同的风格进行详细地讨论。


    6.2.1 递归展开式变量
     第一种风格的变量是递归方式扩展的变量。这一类型变量的定义是通过“=”或者使用指示符“define”定义的。这种变量的引用,在引用的地方是严格的文本替换过程,此变量值的字符串原模原样的出现在引用它的地方。如果此变量定义中存在对其他变量的引用,这些被引用的变量会在它被展开的同时被展开。就是说在变量定义时,变量值中对其他变量的引用不会被替换展开;而是变量在引用它的地方替换展开的同时,它所引用的其它变量才会被一同替换展开。语言的描述可能比较晦涩,让我们来看一个例子:
    foo = $(bar)
    bar = $(ugh)
    ugh = Huh?

    all:;echo $(foo)
    执行“make”将会打印出“Huh?”。整个变量的替换过程时这样的:首先“$(foo)”被替换为“$(bar)”,接下来“$(bar)”被替换为“$(ugh)”,最后“$(ugh)”被替换为“Hug?”。整个替换的过程是在执行“echo $(foo)”时完成的。
    这种类型的变量是其它版本的make所支持的类型。我们可以把这种类型的变量称为“递归展开”式变量。此类型变量存有它的优点同时也存在其缺点。其优点是:
    这种类型变量在定义时,可以引用其它的之前没有定义的变量(可能在后续部分定义,或者是通过make的命令行选项传递的变量)。看一个这样的例子:
    CFLAGS = $(include_dirs) -O
    include_dirs = -Ifoo -Ibar

    “CFLAGS”会在命令中被展开为“-Ifoo -Ibar -O”。而在“CFLAGS”的定义中使用了其后才定义的变量“include_dirs”。
     其缺点是:
     1. 使用此风格的变量定义,可能会由于出现变量的递归定义而导致make陷入到无限的变量展开过程中,最终使make执行失败。例如,接上边的例子,我们给这个变量追加值: 
    CFLAGS = $(CFLAGS) –O
    它将会导致make对变量“CFLAGS”的无限展过程中去(这种定义就是变量的递归定义)。因为一旦后续同样存在对“CLFAGS”定义的追加,展开过程将是套嵌的、不能终止的(在发生这种情况时,make会提示错误信息并结束)。一般书写Makefile时,这种追加变量值的方法很少使用(也不是我们推荐的方式)。看另外一个例子:
    x = $(y)
    y = $(x) $(z)
    这种情况下变量在进行展开时,同样会陷入死循环。所以对于此风格的变量,当在一个变量的定义中需要引用其它的同类型风格的变量时需特别注意,防止变量展开过程的死循环。

    2. 第二个缺点:这种风格的变量定义中如果使用了函数,那么包含在变量值中的函数总会在变量被引用的地方执行(变量被展开时)。
    这是因为在这种风格变量的定义中,对函数引用的替换展开发生在变量展开的过程中,而不是在定义这个变量的时候。这样所带来的问题是:使make的执行效率降低(每一次在变量被展开时都要展开他所引用的函数);另外在某些时候会出现一些变量和函数的引用出现非预期的结果。特别是当变量定义中引用了“shell”和“wildcard”函数的情况,可能出现不可控制或者难以预料的错误,因为我们无法确定它在何时会被展开。

    6.2.2 直接展开式变量
    为了避免“递归展开式”变量存在的问题和不方便。GNU make支持另外一种风格的变量,称为“直接展开”式。这种风格的变量使用“:=”定义。在使用“:=”定义变量时,变量值中对其他量或者函数的引用在定义变量时被展开(对变量进行替换)。所以变量被定义后就是一个实际需要的文本串,其中不再包含任何变量的引用。因此
    x := foo
    y := $(x) bar
    x := later

    就等价于:
    y := foo bar
    x := later


    和递归展开式变量不同:此风格变量在定义时就完成了对所引用变量和函数的展开,因此不能实现对其后定义变量的引用。如:
    CFLAGS := $(include_dirs) -O
    include_dirs := -Ifoo -Ibar
    由于变量“include_dirs”的定义出现在“CFLAGS”定义之后。因此在“CFLAGS”的定义中,“include_dirs”的值为空。“CFLAGS”的值为“-O”而不是“-Ifoo -Ibar -O”。这一点也是直接展开式和递归展开式变量的不同点。注意这里的两个变量都是“直接展开”式的。大家不妨试试将其中某一个变量使用递归展开式定义后看一下又会出现什么样的结果。

     下边我们来看一个复杂一点的例子。分析一下直接展开式变量定义(:=)的用法,这里也用到了make的shell函数和变量“MAKELEVEL”(此变量在make的递归调用时代表make的调用深度)。其中包括了对函数、条件表达式和系统变量“MAKELEVEL”的使用:

    ifeq (0,${MAKELEVEL})
    cur-dir := $(shell pwd)
    whoami := $(shell whoami)
    host-type := $(shell arch)
    MAKE := ${MAKE} host-type=${host-type} whoami=${whoami}
    endif

    第一行是一个条件判断,如果是顶层Makefile,就定义下列变量。否则不定义任何变量。第二、三、四、五行分别定义了一个变量,在进行变量定义时对引用到的其它变量和函数展开。最后结束定义。利用直接展开式的特点我们可以书写这样一个规则:
    ${subdirs}:
    ${MAKE} cur-dir=${cur-dir}/$@ -C $@ all


    它实现了在不同子目录下变量“cur_dir”使用不同的值(为当前工作目录)。
    在复杂的Makefile中,推荐使用直接展开式变量。因为这种风格变量的使用方式和大多数编程语言中的变量使用方式基本上相同。它可以使一个比较复杂的Makefile在一定程度上具有可预测性。而且这种变量允许我们利用之前所定义的值来重新定义它(比如使用某一个函数来对它以前的值进行处理并重新赋值),此方式在Makefile中经常用到。尽量避免和减少递归式变量的使用。 

    详见:http://www.linuxsir.org/main/doc/gnumake/GNUmake_v3.80-zh_CN_html/make-06.html


     

  • 相关阅读:
    MySQL数据库优化
    数据库优化
    shell使用ps -ef|grep xxx时不显示grep xxx进程的方法
    Linux:PS查看进程信息,和查看tomcat内存等信息
    neo4j在linux下的安装
    Markdown 语法整理大集合2017
    TOP 10开源的推荐系统简介
    Molecule – 帮助你构建跨平台的 HTML5 游戏
    精美照片在网页设计中的13个优秀应用案例
    开发中可能会用到的几个 jQuery 小提示和技巧
  • 原文地址:https://www.cnblogs.com/chutianyao/p/2312023.html
Copyright © 2020-2023  润新知