从头开始写项目Makefile(六):参数传递、条件判断、include .

本文详细介绍了在多个Makefile嵌套调用时如何通过使用export关键字和命令行参数传递变量,同时展示了如何利用条件语句(如ifeq、ifneq、ifdef)控制Makefile的执行逻辑。并通过实例展示了如何将规则部分提取到单独的Makefile.rule文件中,以提高Makefile的可维护性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在多个Makefile嵌套调用时,有时我们需要传递一些参数给下一层Makefile。比如我们在顶层Makefile里面定义的打开调试信息变量DEBUG_SYMBOLS,我们希望在进入子目录执行子Makefile时该变量仍然有效,这是需要将该变量传递给子Makefile,那怎么传递呢?这里有两种方法:
1.     在上层Makefile中使用”export”关键字对需要传递的变量进行声明。比如:
  1. DEBUG_SYMBOLS = TRUE  
  2. export DEBUG_SYMBOLS  
DEBUG_SYMBOLS = TRUE
export DEBUG_SYMBOLS
当不希望将一个变量传递给子 make 时,可以使用指示符 “unexport”来声明这个变量。
export一般用法是在定义变量的同时对它进行声明。如下:
  1. export DEBUG_SYMBOLS = TRUE  
export DEBUG_SYMBOLS = TRUE
2.     在命令行上指定变量。比如:
  1. $(MAKE) -C xxx DEBUG_SYMBOLS = TRUE  
$(MAKE) -C xxx DEBUG_SYMBOLS = TRUE
这样在进入子目录xxx执行make时该变量也有效。
 
像编程语言一样,Makefile也有自己的条件语句。条件语句可以根据一个变量值来控制make的执行逻辑。比较常用的条件语句是ifeq –else-endif、ifneq-else-endif、ifdef-else-endif。
ifeq关键字用来判断参数是否相等。
比如判断是否生成调试信息可以这么用:
  1. ifeq ($(DEBUG_SYMBOLS), TRUE)  
  2. >---CFLAGS += -g -Wall -Werror -O0  
  3. else  
  4. >---CFLAGS += -Wall -Werror -O2  
  5. endif  
  6.    
ifeq ($(DEBUG_SYMBOLS), TRUE)
>---CFLAGS += -g -Wall -Werror -O0
else
>---CFLAGS += -Wall -Werror -O2
endif
 
Ifneq和ifeq作用相反,此关键字是用来判断参数是否不相等。
ifdef关键字用来判断一个变量是否已经定义。
后两个关键字用法和ifeq类似。
 
现在我们继续改进我们上一节的Makefile,上一节的Makefile完成Makefile的嵌套调用,每一个模块都有自己的Makefile。其实每个模块的Makefile都大同小异,只需要改改最后编译成生成的目标名称或者编译链接选项,规则都差不多,那么我们是否可以考虑将规则部分提取出来,每个模块只需修改各自变量即可。这样是可行的,我们将规则单独提取出来,写一个Makefile.rule,将他放在顶层Makefile同目录下,其他模块内部的Makefile只需要include该Makefile就可以了。如下:
  1. include $(SRC_BASE)/Makefile.rule  
include $(SRC_BASE)/Makefile.rule
include类似于C语言的头文件包含,你把它理解为为本替换就什么都明白了。
这样以后规则有修改的话我们直接修改该Makefile就可以了,就不用进入每一个模块去修改,这样也便于维护。
这样我们今天顶层Makefile稍作修改:
  1. # Top Makefile for C program                                                                                                                                                               
  2. # Copyright (C) 2014 shallnew \at 163 \dot com  
  3.    
  4. export DEBUG_SYMBOLS = TRUE  
  5.    
  6. DIR = src  
  7. MODULES = $(shell ls $(DIR))  
  8. MODULES = ipc main tools  
  9.    
  10. all : $(MODULES)  
  11.    
  12. $(MODULES):  
  13. >---$(MAKE) -C $(DIR)/$@  
  14.    
  15. main:tools ipc  
  16.    
  17. clean :  
  18. >---@for subdir in $(MODULES); \  
  19. >---do $(MAKE) -C $(DIR)/$$subdir $@; \  
  20. >---done  
  21.    
  22. distclean:  
  23. >---@for subdir in $(MODULES); \  
  24. >---do $(MAKE) -C $(DIR)/$$subdir $@; \  
  25. >---done  
  26.    
  27. tags:  
  28. >---ctags -R  
  29.    
  30. help:  
  31. >---@echo "===============A common Makefilefor c programs=============="  
  32. >---@echo "Copyright (C) 2014 liuy0711 \at 163\dot com"  
  33. >---@echo "The following targets aresupport:"  
  34. >---@echo  
  35. >---@echo " all              - (==make) compile and link"  
  36. >---@echo " clean            - clean target"  
  37. >---@echo " distclean        - clean target and otherinformation"  
  38. >---@echo " tags             - create ctags for vimeditor"  
  39. >---@echo " help             - print help information"  
  40. >---@echo  
  41. >---@echo "To make a target, do 'make[target]'"  
  42. >---@echo "========================= Version2.2 ======================="  
  43.    
  44. .PHONY : all clean distclean tags help  
  45.    
# Top Makefile for C program                                                                                                                                                             
# Copyright (C) 2014 shallnew \at 163 \dot com
 
export DEBUG_SYMBOLS = TRUE
 
DIR = src
MODULES = $(shell ls $(DIR))
# MODULES = ipc main tools
 
all : $(MODULES)
 
$(MODULES):
>---$(MAKE) -C $(DIR)/$@
 
main:tools ipc
 
clean :
>---@for subdir in $(MODULES); \
>---do $(MAKE) -C $(DIR)/$$subdir $@; \
>---done
 
distclean:
>---@for subdir in $(MODULES); \
>---do $(MAKE) -C $(DIR)/$$subdir $@; \
>---done
 
tags:
>---ctags -R
 
help:
>---@echo "===============A common Makefilefor c programs=============="
>---@echo "Copyright (C) 2014 liuy0711 \at 163\dot com"
>---@echo "The following targets aresupport:"
>---@echo
>---@echo " all              - (==make) compile and link"
>---@echo " clean            - clean target"
>---@echo " distclean        - clean target and otherinformation"
>---@echo " tags             - create ctags for vimeditor"
>---@echo " help             - print help information"
>---@echo
>---@echo "To make a target, do 'make[target]'"
>---@echo "========================= Version2.2 ======================="
 
.PHONY : all clean distclean tags help
 
目前我们顶层目录下的目录树为:
  1. .  
  2. ├── include  
  3. │   ├── common.h  
  4. │   ├── ipc  
  5. │   │   └── ipc.h  
  6. │   └── tools  
  7. │       ├── base64.h  
  8. │       ├── md5.h  
  9. │       └── tools.h  
  10. ├── libs  
  11. ├── Makefile  
  12. ├── Makefile.rule  
  13. └── src  
  14.     ├── ipc  
  15.     │  ├──inc  
  16.     │  ├──Makefile  
  17.     │  └──src  
  18.     │       └── ipc.c  
  19.     ├── main  
  20.     │  ├──inc  
  21.     │  ├──Makefile  
  22.     │  └──src  
  23.     │       ├── main.c  
  24.     │       └── main.c~  
  25.     └── tools  
  26.         ├── inc  
  27.         ├── Makefile  
  28.         └── src  
  29.             ├── base64.c  
  30.             ├── md5.c  
  31.             └── tools.c  
  32.    
  33. 14 directories, 16 files  
  34.    
.
├── include
│   ├── common.h
│   ├── ipc
│   │   └── ipc.h
│   └── tools
│       ├── base64.h
│       ├── md5.h
│       └── tools.h
├── libs
├── Makefile
├── Makefile.rule
└── src
    ├── ipc
    │  ├──inc
    │  ├──Makefile
    │  └──src
    │       └── ipc.c
    ├── main
    │  ├──inc
    │  ├──Makefile
    │  └──src
    │       ├── main.c
    │       └── main.c~
    └── tools
        ├── inc
        ├── Makefile
        └── src
            ├── base64.c
            ├── md5.c
            └── tools.c
 
14 directories, 16 files
 
每个子模块下的Makefile删除规则后修改为如下:
 
  1. SRC_BASE = ../..  
  2.    
  3. CFLAGS +=  
  4. CPPFLAGS += -I. -I./inc -I$(SRC_BASE)/include  
  5.    
  6. SRC_OBJ = $(patsubst %.c, %.o, $(wildcard *.c))  
  7. SRC_FILES = $(wildcard src/*.c)  
  8. SRC_OBJ = $(SRC_FILES:.c=.o)  
  9. SRC_LIB = libtools.a  
  10.    
  11. include $(SRC_BASE)/Makefile.rule  
SRC_BASE = ../..
 
CFLAGS +=
CPPFLAGS += -I. -I./inc -I$(SRC_BASE)/include
 
# SRC_OBJ = $(patsubst %.c, %.o, $(wildcard *.c))
SRC_FILES = $(wildcard src/*.c)
SRC_OBJ = $(SRC_FILES:.c=.o)
SRC_LIB = libtools.a
 
include $(SRC_BASE)/Makefile.rule
<think>好的,我现在需要解决用户遇到的编译器警告问题,具体是关于函数'nla_parse'未声明的隐式函数声明错误。用户提供的引用内容主要涉及在CentOS上安装ipvsadm-1.26时遇到的依赖问题和Makefile修改,但当前问题涉及的是编译时nla_parse函数的未声明错误。我需要先理解这个错误的原因,然后找到解决方法。 首先,隐式函数声明错误通常是因为编译器在函数使用前没有找到对应的声明,也就是头文件未被正确包含。nla_parse函数属于Netlink库(libnl)的一部分,通常用于解析Netlink属性。因此,问题可能出在缺少相关的头文件包含或者库版本不兼容。 接下来,我需要检查用户的环境。用户提到的系统是CentOS 6.x,安装的libnl版本是1.1-14.el6。而libnl3的版本可能更高,可能函数定义有所不同。nla_parse可能在libnl3中被修改或重命名,例如可能需要包含不同的头文件路径或者函数参数发生了变化。 根据引用中的信息,用户已经安装了libnl-devel和popt-devel,所以依赖库应该是存在的。但可能在编译时,头文件路径没有正确指向libnl3的路径。例如,旧的Makefile可能仍然指向旧版libnl的头文件,或者没有包含正确的路径。 查看用户提供的引用4,其中提到修改Makefile中的INCLUDE路径,将内核头文件路径指向正确的位置。可能需要类似的操作,将libnl的头文件路径包含进去。例如,添加-I/usr/include/libnl3或其他相关路径。 另外,可能需要检查函数签名是否匹配。在libnl的不同版本中,nla_parse的参数可能有所不同。例如,libnl3中的nla_parse可能需要额外的参数,如策略(policy)参数,而旧版本可能没有。如果代码中的函数调用缺少必要的参数,就会导致编译器报错。 此外,隐式声明还可能引发警告,因为编译器会假定函数的返回类型为int,而实际可能不是,导致潜在的问题。因此,解决这个问题不仅是消除警告,更是确保代码正确性。 可能的解决步骤包括: 1. 确认libnl3-devel是否安装,因为旧版的libnl可能不包含所需的函数定义。 2. 在代码中包含正确的头文件,例如#include <netlink/netlink.h> 或 #include <netlink/attr.h>。 3. 检查Makefile中的INCLUDE路径,确保指向libnl3的头文件目录,如添加-I/usr/include/libnl3。 4. 检查nla_parse函数的调用方式,确保参数与库版本匹配。例如,libnl3可能要求传递策略结构体作为参数。 5. 如果使用的libnl版本过旧,可能需要升级到更高版本,或修改代码以适应旧版API。 参考用户提供的引用4中的做法,修改MakefileINCLUDE路径可能是关键。例如,如果libnl3的头文件位于/usr/include/libnl3,则需要在编译指令中添加该路径。 此外,可能需要检查函数是否存在。例如,使用nm命令查看libnl库中是否存在nla_parse符号,或者检查文档确认该函数在特定版本中的存在性。 最后,如果所有方法都无法解决,可能需要查找该问题的已知解决方案,如社区或论坛中是否有类似的问题,或者参考官方文档的迁移指南,了解从旧版libnl迁移到新版时的API变化。</think>要解决编译时出现的`nla_parse`隐式函数声明错误,需从头文件包含和库版本兼容性两方面入手。以下是具体解决方案: --- ### **步骤1:确认libnl开发包版本** 隐式声明通常由缺少头文件引起。执行以下命令验证是否安装了**libnl3**开发包: ```bash rpm -qa | grep libnl-devel ``` 若输出为`libnl-devel-1.1-14.el6`,说明系统安装的是**libnl1**,而`nla_parse`函数在**libnl3**中定义[^2][^3]。需升级到libnl3: ```bash yum install libnl3-devel ``` --- ### **步骤2:修改Makefile包含路径** 在`ipvsadm`源码目录中,修改**Makefile**以包含libnl3的头文件路径: ```makefile # 原INCLUDE行可能类似: INCLUDE = -I/usr/include # 修改为: INCLUDE = -I/usr/include/libnl3 -I/usr/include ``` 此举确保编译器能找到`netlink/netlink.h`等头文件[^4]。 --- ### **步骤3:检查函数参数兼容性** `nla_parse`在不同版本中的参数差异: - **libnl1**:`int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len);` - **libnl3**:`int nla_parse(struct nlattr *tb[], int maxtype, struct nlattr *head, int len, struct nla_policy *policy);` 需在代码中添加**策略参数**(policy),例如: ```c struct nla_policy policy[MAX_ATTR] = { /* 定义策略 */ }; nla_parse(tb, MAX_ATTR, head, len, policy); ``` --- ### **步骤4:验证链接库路径** 在Makefile的链接阶段添加`-lnl-3`以链接libnl3库: ```makefile LIBS = -lpopt -lnl-3 ``` 若存在多版本库,可通过`ldconfig -p | grep libnl`确认路径。 --- ### **步骤5:清理并重新编译** ```bash make clean && make ``` --- ### **原理说明** 隐式函数声明错误表明编译器未找到函数原型。通过包含正确的头文件路径(如`libnl3`)并适配API参数,可解决兼容性问题[^5]。若仍报错,需检查库版本是否与代码预期一致。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值