yyxl的个人空间 https://blog.eetop.cn/201358 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

make 编译目标目录(原)

已有 3351 次阅读| 2010-4-10 21:30 |个人分类:linux内核

 可能好多朋友都希望在编译的时候,不想把目标文件、中间文件编译在源目录下面。因为这样看上去或许有点混乱,更希望把目标文件、中间文件等编译到一个目录中。原来我也试过多种方法,在gcc命令中使用绝对路径,虽然成功了,但却不尽人意,导致makefile不简洁,不易修改维护,如果存在多个目录,就会更显得臃肿。所以今天我就来给大家介绍一个方法,简介,直观,易于维护。好,现在我们就来实现把src目录下的源文件编译到objs目录下。

假设我们有这样的一个目录结构
test---
...|---objs          //目录
...|---src           //目录 包含 main.c yuer.c
...|---include       //目录 包含 yuer.h
...|---Makefile         //文件
...|---environment.mak //文件
...|---builddir.mak     //文件

你可以点击这里获取源代码


在test文件夹中有三个子目录,分别存放目标文件、源文件、头文件;我们假设在src目录中有main.c yuer.c 在include目录中yuer.h。然后我们把我们的Makefile放置在test目录下(即根目录下),当然我们也可以放置在源目录下,只需作一点点修改;

我们这个makefile的目标是为了达到简洁,直观,并且易于维护,实现在集中目标文件的功能,所以我们将建立多个子makefile,共同来完成我们的目标;

注解:
environment.mak 定义全局变量,命令等
buildir.mak       检测编译目录,在目标目录中调用make
Makefile          简洁,直观,易于维护的makefile

内容:
environment.mak
#---------------------------------------------------------
# 设置命令变量
#---------------------------------------------------------

CC    = gcc
RM    = rm
ECHO = echo
MKDIR = mkdir
RMDIR = rmdir

# 定义一个当前编译目录变量
BUILDING_DIR := $(shell pwd)

builddir.mak
#---------------------------------------------------------
#
包含environment.mak
#---------------------------------------------------------

include /home/yuqiang/桌面/test/environment.mak

# 这个宏变量用于删除目标文件
define TARGET_CLEAN
$(MAKE) -C $(BUILDING_DIR)/objs -f $(BUILD_DIR)/Makefile IN_OBJECT_DIR=1 $@
endef

#---------------------------------------------------------
# 默认目标
#---------------------------------------------------------

default:check_dir
$(MAKE) -C $(BUILDING_DIR)/objs -f $(BUILDING_DIR)/Makefile IN_OBJECT_DIR=1

# 检查目标目录是否存在

check_dir:
ifeq "$(wildcard objs)" ""
@$(MKDIR) -p objs
endif

#---------------------------------------------------------
# 删除目标文件和objs目录
#---------------------------------------------------------

clean:
$(TARGET_CLEAN)
@$(ECHO) Remove dir: objs
-@$(RMDIR) objs


Makefile
ifdef IN_OBJECT_DIR
#---------------------------------------------------------
#
包含environment.mak
#---------------------------------------------------------

include /home/yuqiang/桌面/test/environment.mak

# 定义源文件搜索路径

vpath %.c /home/yuqiang/桌面/test/src

TARGETS := myapp
OBJS    := yuer.o main.o

#---------------------------------------------------------
# 设置编译参数变量
#---------------------------------------------------------

INCLUDES := -I/home/yuqiang/桌面/test/include
CFLAGS   += $(INCLUDES)

default:$(TARGETS)

$(TARGETS):$(OBJS)
@$(ECHO) Creating $@ ...
@$(CC) $^ -o $@

%.o:%.c
@$(ECHO) Compiling $@ ...
@$(CC) $(CFLAGS) -c $< -o $@

clean:
@$(ECHO) Cleaning $(OBJS) ...
@$(ECHO) Cleaning $(TARGETS) ...
-@$(RM) -f *.o
-@$(RM) -f $(TARGETS)
else
include /home/yuqiang/桌面/test/builddir.mak
endif

注意:
1,此makefile在linux下面的shell运行,如果是在windows下面,要稍微修改一点点,理解原理后可自行修改

2,因为此makefile使用了vpath关键字,所以在gcc命令中,请务必使用自动变量$^ $@ $<,而不要直接使用依赖文件。具体原因清看GNU makefile 3.8

3,在environment.mak中的BUILDING_DIR变量,在不同的时候值是不一样的。在builddir.mak中时为/home/yuqiang/桌面/test/ 在Makefile中是为/home/yuqiang/桌面/test/objs

4,你可能会发现在Makefile和builddir.mak中都一个default目标,会不会产生冲突。不会的,因为他们不可能同时存在。

解释:
为了让你更好的理解此makefile工作的原理,我在这里解释一下,它的工作流程,以便你更快的读懂。

当我们做完所有的工作之后,我们就可以在终端执行make了,当我们输入make的时候,由于Makefile中的IN_OBJECT_DIR未定义的,所以不包含ifdef IN_OBJECT_DIR到else中间的代码,而是else到endif之间的代码,相当于,Makefile仅由一句话include /home/yuqiang/桌面/test/builddir.mak组成。

所以当你输入make的时候,首先执行builddir.mak中的内容,检查objs目录是否存在,不存在则创建,然后在builddir.mak中自动调用make命令,而此时的make命令把一个宏IN_OBJECT_DIR=1传递到了他要调用的makfile中,所以这次调用make时Makefile的内容为ifdef IN_OBJECT_DIR到else之间的内容,创建目标文件和可执行文件。

删除目标文件和目录原理相似

建议:
你已经看到了,我们这样写include /home/yuqiang/桌面/test/builddir.mak其实很不方便的,如果我的test换在了其他的目录下,我们每次都要修改这些地方,不方便,也不简洁,还容易出错,所以我建议,我们可以创建一个shell文件(set.sh)来设置一些变量。把这个set.sh加到test文件夹中。

set.sh
#! /bin/sh

# 不打印目录
MAKEFLAGS:=--no-print-directory

# 清除环境变量
unset YUER_ROOT
unset YUER_INCLUDE
unset YUER_MAKE

# 导出环境变量
export   YUER_ROOT=`pwd`
export   YUER_INCLUDE=$(YUER_ROOT)/include
export   YUER_MAKE=$(YUER_ROOT)/make

if [ -z YUER_ROOT ];then
echo "环境配置成功!"
else
echo "环境配置失败"
fi

这样之后,我们的makefile中的include /home/yuqiang/桌面/test/builddir.mak ... 就可以写成
include $(YUER_ROOT)/environment.mak
include $(YUER_ROOT)/builddir.mak

这样做的好处是,可以更好的移植我们的Make系统,我们还可以把通用文件(%.mak)通过一个变量YUER_MAKE放置到一个目录中,同一管理,多次使用。在你输入make之前,在test目录下运行 source set.sh然后在运行make就可以了。非常方便使用。还有很多的好处,我就不再赘述,等待你自己去发现了。

运行:
$ make
Compiling yuer.o ...
Compiling main.o ...
Creating myapp ...

$ make clean
Cleaning function.o main.o ...
Cleaning myapp ...
Remove dir: objs


点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 1

    粉丝
  • 0

    好友
  • 0

    获赞
  • 0

    评论
  • 973

    访问数

小黑屋| 手机版| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-11-5 09:15 , Processed in 0.015232 second(s), 7 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部