查看原文
其他

Windows 环境下的 makefile 编写要点

CPP开发者 2021-09-08

The following article is from 探索文字之美 Author 朱金灿

(给CPP开发者加星标,提升C/C++技能)

作者: 探索文字之美/ 朱金灿 (本文来自作者投稿)

一.Windows环境下的makefile的基本套路

据我观察,Windows环境下是存在一个makefile的基本套路的,具体如下:

1.设置编译标记

2.假如编译标记不对,就提示用法

3.假如执行清理命令,则执行清理命令

4.设置编译输出(包含输出文件夹、exe文件或dll文件等)

5.创建输出文件夹之类(这步可选)

6.运行编译命令,生成目标文件

7.运行资源编译命令(如果没有资源文件,这步不用)

8.运行链接命令生成exe或dll文件

二.我设计的一套makefile模板

很多开源库设置了很多编译选项,比如gdal库,就设置了如下不同的编译命令:

nmake -f makefile.vc DEBUG=1// 编译32位的debug版本

nmake -f makefile.vc
//编译32位的release版本

nmake -f makefile.vc WIN64=
1 DEBUG=1//编译64位的debug版本

nmake -f makefile.vc WIN64=
1//编译64位的release版本

nmake -f makefile.vc clean
// 清理编译

nmake -f makefile.vc devinstall WIN64=
1// 编译release版本并安装开发头文件和库文件
这种设计并不好,因为用户无法记住这么多的编译选项。人性化的设计应该是只有一个编译选项,用户根据这个编译选项来确定编译什么版本,比如nmake /f makefile.vc option=x,这个x的取值范围是1到5。还是用我编写的例子来说明:

#包含基本的环境变量

!include <C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Include\Win32.Mak>

#设置编译标记,初始化为FALSE
CFGSET = FALSE

!IF
"$(option)"== "1"
\program>

#下面是编译选项1的设置
CFGSET = TRUE

Platform= x64
Configuration= Release
\program>

#定义release版本的预处理器
CC_OPTION = -D_WIN64 -D_NDEBUG -D_WINDOWS

TARGET_MACHINE = X64

!ELSE IF
"$(option)"== "2"
\program>

#下面是编译选项2的设置
CFGSET = TRUE

Configuration= Debug
\program>

Platform= x64
#定义debug版本的编译选项
CC_OPTION = -D_WIN64 -D_DEBUG -D_WINDOWS

TARGET_MACHINE = X64

!ELSE IF
"$(option)"== "3"
\program>

#下面是编译选项3的设置
CFGSET = TRUE

Configuration= Release
\program>

Platform= Win32
CC_OPTION = -D_WIN32 -D_NDEBUG -D_WINDOWS

TARGET_MACHINE = X86

!ELSE IF
"$(option)"== "4"
\program>

#下面是编译选项4的设置
CFGSET = TRUE

Configuration= Debug
\program>

Platform= Win32
CC_OPTION = -D_WIN32 -D_DEBUG -D_WINDOWS

TARGET_MACHINE = X86

!ELSE IF
"$(option)"=="5"

CFGSET=TRUE

!ENDIF

# 提示用法
\program>

!IF "$(CFGSET)"== "FALSE"!MESSAGE Usage: nmake /f makefile.vc option=1or2or3or4or5
!MESSAGE
!MESSAGE
whereis one of:!MESSAGE - option=1- build x64 release version
!MESSAGE - option=
2- build x64 debug version
!MESSAGE - option=
3- build x86 release version
!MESSAGE - option=
4- build x86 debug version
!MESSAGE - option=
5- clear temp file and output file
!MESSAGE
!MESSAGE
!ERROR please choose a valid configuration instead
"
!ENDIF

#假如编译选项为5,则执行清理操作
!IF "
$(option)"=="5"
CLEAN:
if exist "
..\..\Intdir\Debug_x64\MyDepends" (del "..\..\Intdir\Debug_x64\MyDepends\*.obj") else echo Debug_x64 not exist
if exist "
..\..\Intdir\Debug_Win32\MyDepends" (del "..\..\Intdir\Debug_Win32\MyDepends\*.obj") else echo Debug_Win32 not exist
if exist "
..\..\Intdir\Release_x64\MyDepends" (del "..\..\Intdir\Release_x64\MyDepends\*.obj") else echo Release_x64 not exist
if exist "
..\..\Intdir\Release_Win32\MyDepends" (del "..\..\Intdir\Release_Win32\MyDepends\*.obj") else echo Release_Win32 not exist

!ELSE

#设置输出文件夹和临时文件夹
OUTDIR =..\..\OutDir\$(Configuration)_$(Platform)
INDIR =..\..\Intdir\$(Configuration)_$(Platform)\MyDepends

#这里增加多个输出
all: $(INDIR) $(INDIR)\MyDepends.res $(OUTDIR) $(OUTDIR)\MyDepends.exe

#假如不存在$(INDIR)文件夹,就创建它
$(INDIR) :
if not exist "
$(INDIR)" mkdir $(INDIR)

#假如不存在$(OUTDIR)文件夹,就创建它
$(OUTDIR) :
if not exist "
$(OUTDIR)" mkdir $(OUTDIR)

#运行编译命令
CC = $(CC_OPTION)

$(INDIR)\MessageProcess.obj:MessageProcess.c
cl -c $(CC) /Fo"
$(INDIR)\\" /Fd"$(INDIR)\\" MessageProcess.c

$(INDIR)\MyDepends.obj:MyDepends.c $(INDIR)\MessageProcess.obj
cl -c $(CC) /Fo"
$(INDIR)\\" /Fd"$(INDIR)\\" MyDepends.c

#编译资源脚本
$(INDIR)\MyDepends.res:MyDepends.rc
rc.exe /n /v /fo $(INDIR)\MyDepends.res MyDepends.rc

#运行链接命令
$(OUTDIR)\MyDepends.exe: $(INDIR)\MyDepends.obj
link /machine:$(TARGET_MACHINE) /NOLOGO /subsystem:WINDOWS /out:$(OUTDIR)\MyDepends.exe $(INDIR)\MyDepends.obj $(INDIR)\MessageProcess.obj $(INDIR)\MyDepends.res kernel32.lib user32.lib comdlg32.lib Shell32.lib
!ENDIF
\program>

可以看出nmake /f makefile.vc option=1编译的是64位的release版本,nmake /f makefile.vc option=2编译的是64位的debug版本,nmake /f makefile.vc option=3编译的是32位的release版本,nmake /f makefile.vc option=4编译的是32位的debug版本,nmake /f makefile.vc option=5执行的是清理输出文件的操作。
假如用户输出了nmake /f makefile.vc option=6呢?那么就会出现以下提示:

三.编写Windows环境下的makefile的注意事项

原来清理输出的命令我是这样写的:
!IF "$(RUN_CLEAN)"== "TRUE"if exist "../../Intdir/Debug_x64/TestLog"(del"..\..\Intdir\Debug_x64\TestLog\*.obj") else echo Debug_x64不存在if exist "../../Intdir/Debug_Win32/TestLog"(del"..\..\Intdir\Debug_Win32\TestLog\*.obj") else echo Debug_Win32不存在!ELSE
结果出现错误,如下图:

需要修改为:

!IF "$(RUN_CLEAN)"== "TRUE"
CLEAN:
if exist "..\..\Intdir\Debug_x64\TestLog"(del"..\..\Intdir\Debug_x64\TestLog\*.obj") else echo Debug_x64not exist
if exist "..\..\Intdir\Debug_Win32\TestLog"(del"..\..\Intdir\Debug_Win32\TestLog\*.obj") else echo Debug_Win32not exist
if exist "..\..\Intdir\Release_x64\TestLog"(del"..\..\Intdir\Release_x64\TestLog\*.obj") else echo Release_x64not exist
if exist "..\..\Intdir\Release_Win32\TestLog"(del"..\..\Intdir\Release_Win32\TestLog\*.obj") else echo Release_Win32not exist

!ELSE
关键点有三点:

1.必须增加一个块名,比如这里添加了CLEAN:

2.CLEAN:和if exist之间不能有空行。

3.if exist之前至少得插入一个tab。


【本文作者】


作者:朱金灿,本科毕业于CUG(武汉)的GIS专业。目前在北京从事软件开发和团队管理工作。曾获有色金属工业科技进步奖二等奖。
个人博客:https://blog.csdn.net/clever101。微信公众号:HiProgrammer



推荐阅读

(点击标题可跳转阅读)

初识 MakefIle

微软新编程字体开源,用着一不小心就骂人了



看完本文有帮助?请分享给更多人

关注「CPP开发者」加星标,提升C/C++技能

好文章,我在看❤️

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存