nmake文件学习记录看《跟我一起写Makefile》

Posted xiaokcehui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了nmake文件学习记录看《跟我一起写Makefile》相关的知识,希望对你有一定的参考价值。

1、陈皓《跟我一起写Makefile》

makefile 带来的好处就是——“自动化编译”,一旦写好,只需要一个make 命令,整个工程完全自动编译,极大的提高了软件开发的效率。

make 是一个命令工具,是一个解释makefile 中指令的命令工具,一般来说,大多数的IDE 都有这个命令,比如:Delphi的make,VisualC++的nmake,Linux 下GNU 的make。可见,makefile 都成为了一种在工程方面的编译方法。

NMAKE 生成文件内容和功能 | Microsoft Learn

NMAKE的命令行语法_唐竹的博客-CSDN博客_nmake 语法

nmake -HELP,nmake /HELP等价

CL 编译器选项总结_DAGiGi的博客-CSDN博客_cl 编译选项

CL 与 LINK的命令行用法_t0nsha的博客-CSDN博客_cl link

CL命令的例子

/GS /TP /W3 /Zc:wchar_t /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\vs2017-64\\qCC" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\qCC" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\vs2017-64\\qCC\\CloudCompare_autogen\\include_Debug" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\contrib\\shapelib" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\libs\\CCFbo\\include" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\CC\\include" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\libs\\qCC_db" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\libs\\qCC_db\\msvc" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\libs\\qCC_io" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\libs\\qCC_glWindow" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\plugins" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\qCC\\..\\common" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\qCC\\db_tree" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\qCC\\ui_templates" /I"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\CloudCompare-2.11.3\\qCC\\..\\libs\\qcustomplot" /I"C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\include" /I"C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\include\\QtOpenGL" /I"C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\include\\QtWidgets" /I"C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\include\\QtGui" /I"C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\include\\QtCore" /I"C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\.\\mkspecs\\win32-msvc" /I"C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\include\\QtANGLE" /I"C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\include\\QtConcurrent" /I"C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\include\\QtPrintSupport" /I"C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\include\\QtOpenGLExtensions" /Zi /Gm- /Od /Ob0 /Fd"CloudCompare.dir\\Debug\\vc141.pdb" /Zc:inline /fp:precise /D "WIN32" /D "_WINDOWS" /D "CC_SHP_SUPPORT" /D "NOMINMAX" /D "_CRT_SECURE_NO_WARNINGS" /D "__STDC_LIMIT_MACROS" /D "SCALAR_TYPE_FLOAT" /D "QT_USE_QSTRINGBUILDER" /D "QT_CORE_LIB" /D "QT_OPENGL_LIB" /D "QT_WIDGETS_LIB" /D "QT_GUI_LIB" /D "QT_OPENGLEXTENSIONS_LIB" /D "QT_CONCURRENT_LIB" /D "QT_PRINTSUPPORT_LIB" /D "CMAKE_INTDIR=\\"Debug\\"" /D "_MBCS" /errorReport:prompt /WX- /Zc:forScope /RTC1 /GR /Gd /MDd /openmp /Fa"Debug/" /EHsc /nologo /Fo"CloudCompare.dir\\Debug\\" /Fp"CloudCompare.dir\\Debug\\CloudCompare.pch" /diagnostics:classic 

LINK命令例子

/OUT:"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\vs2017-64\\qCC\\Debug\\CloudCompare.exe" /MANIFEST:NO /NXCOMPAT /PDB:"D:/OceanMultiBeamProc/CloudCompare-2.11.3/vs2017-64/qCC/Debug/CloudCompare.pdb" /DYNAMICBASE "..\\libs\\CCFbo\\Debug\\CC_FBO_LIBd.lib" "..\\libs\\qCC_io\\Debug\\QCC_IO_LIBd.lib" "..\\libs\\qCC_glWindow\\Debug\\QCC_GL_LIBd.lib" "..\\libs\\qcustomplot\\Debug\\qcustomplotd.lib" "C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\lib\\Qt5PrintSupportd.lib" "C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\lib\\qtmaind.lib" "..\\contrib\\shapelib\\Debug\\SHAPELIBd.lib" "..\\libs\\qCC_db\\Debug\\QCC_DB_LIBd.lib" "..\\CC\\Debug\\CC_CORE_LIBd.lib" "C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\lib\\Qt5Widgetsd.lib" "C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\lib\\Qt5Guid.lib" "C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\lib\\Qt5Concurrentd.lib" "C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\lib\\Qt5Cored.lib" "C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\lib\\Qt5OpenGLd.lib" "C:\\Qt\\Qt5.12.0\\5.12.0\\msvc2017_64\\lib\\Qt5OpenGLExtensionsd.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "winspool.lib" "shell32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "comdlg32.lib" "advapi32.lib" /IMPLIB:"D:/OceanMultiBeamProc/CloudCompare-2.11.3/vs2017-64/qCC/Debug/CloudCompare.lib" /DEBUG /MACHINE:X64 /INCREMENTAL /PGD:"D:\\OceanMultiBeamProc\\CloudCompare-2.11.3\\vs2017-64\\qCC\\Debug\\CloudCompare.pgd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /ManifestFile:"CloudCompare.dir\\Debug\\CloudCompare.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1 

WIN32 预定义宏WIN32,_WIN32,_WIN64介绍使用_kevin--你不知道的事的博客-CSDN博客_win32宏定义

一般来说,无论是C、C++、还是pas,首先要把源文件编译成中间代码文件,在Windows
下也就是.obj 文件,UNIX 下是.o 文件,即Object File,这个动作叫做编译(compile)。然后再把大量的Object File 合成执行文件,这个动作叫作链接(link)。

链接时,主要是链接函数和全局变量,所以,我们可以使用这些中间目标文件(O 文件或是OBJ 文件)来链接我们的应用程序。链接器并不管函数所在的源文件,只管函数的中间目标文件(Object File),在大多数时候,由于源文件太多,编译生成的中间目标文件太多,而在链接时需要明显地指出中间目标文件名,这对于编译很不方便,所以,我们要给中间目标文件打个包,在Windows 下这种包叫“库文件”(Library File),也就是.lib 文件,在UNIX 下,是Archive File,也
就是.a 文件。

Makefile 里主要包含了五个东西:显式规则、隐晦规则、变量定义、文件指示和注释。
1、显式规则。显式规则说明了,如何生成一个或多的的目标文件。这是由Makefile 的书写者明显指出,要生成的文件,文件的依赖文件,生成的命令。
2、隐晦规则。由于我们的make 有自动推导的功能,所以隐晦的规则可以让我们比较粗糙地简略地书写Makefile,这是由make 所支持的。
3、变量的定义。在Makefile 中我们要定义一系列的变量,变量一般都是字符串,这个有点你C 语言中的宏,当Makefile 被执行时,其中的变量都会被扩展到相应的引用位置上。
4、文件指示。其包括了三个部分,一个是在一个Makefile 中引用另一个Makefile,就像C 语言中的include 一样;另一个是指根据某些情况指定Makefile 中的有效部分,就像C 语言中的预编译#if 一样;还有就是定义一个多行的命令。有关这一部分的内容,我会在后续的部分中讲述。
5、注释。Makefile 中只有行注释,和UNIX 的Shell脚本一样,其注释是用“#”字符,这个就像C/C++中的“//”一样。如果你要在你的Makefile 中使用“#”字符,可以用反斜框进行转义,如:“\\#”。最后,还值得一提的是,在Makefile 中的命令,必须要以[Tab]键开始。

STATICLIB = $(LIBDIR)/mbgsf_static.lib   //NMAKE宏
OBJS = gsf.obj gsf_dec.obj gsf_enc.obj gsf_indx.obj gsf_info.obj     //NMAKE宏
AR = lib   //NMAKE宏,LIB命令
$(STATICLIB): $(OBJS)   //NMAKE 目标:依赖
    $(AR) -out:$@ $(OBJS)    //NMAKE 命令 LIB -OUT:filename,$@,特殊的NMAKE宏,指当前指定的当前目标的全名(路径、基本名称、扩展名)。

如果你想让make 不理那些无法读取的文件,而继续执行,你可以在include 前加一个减号“-”。如:-include <filename>
其表示,无论include 过程中出现什么错误,都不要报错继续执行。和其它版本make 兼容的相关命令是sinclude,其作用和这一个是一
样的。

GNU 的make 工作时的执行步骤入下:(想来其它的make 也是类似)
1、读入所有的Makefile。
2、读入被include 的其它Makefile。
3、初始化文件中的变量。
4、推导隐晦规则,并分析所有规则。
5、为所有的目标文件创建依赖关系链。
6、根据依赖关系,决定哪些目标要重新生成。
7、执行生成命令。

嵌套执行make
在一些大的工程中,我们会把我们不同模块或是不同功能的源文件放在不同的目录中,我们可以在每个目录中都书写一个该目录的Makefile,这有利于让我们的Makefile 变得更加地简洁,而不至于把所有的东西全部写在一个Makefile 中,这样会很难维护我们的Makefile,这个技术对于我们模块编译和分段编译有着非常大的好处。
例如,我们有一个子目录叫subdir,这个目录下有个Makefile 文件,来指明了这个目录下文件的编译规则。那么我们总控的Makefile 可以这样书写:
subsystem:
cd subdir && $(MAKE)
其等价于:
subsystem:
$(MAKE) -C subdir
定义$(MAKE)宏变量的意思是,也许我们的make 需要一些参数,所以定义成一个变量比较利于维护。这两个例子的意思都是先进入“subdir”目录,然后执行make 命令。
我们把这个Makefile 叫做“总控Makefile”,总控Makefile 的变量可以传递到下级的Makefile 中(如果你显示的声明),但是不会覆盖下层的Makefile 中所定义的变量,除非指定了“-e”参数。如果你要传递变量到下级Makefile 中,那么你可以使用这样的声明:
export <variable ...>
如果你不想让某些变量传递到下级Makefile 中,那么你可以这样声明:
unexport <variable ...>

gmt_dir:    //伪目标,总是被执行
    cd src/gmt     //到src/gmt目录
    $(MAKE) /f makefile.vc   //$(MAKE),递归宏,属于特殊宏, 提供了 nmake.exe 的完整路径
    cd ../..   //回到src的父目录

nmake详解 - bw_0927 - 博客园

Makefile 中:= ?= += =的区别 - wanqi - 博客园

Makefile之patsubst - Geeking - 博客园

Makefile 里的 subst 函数_prettykernel的博客-CSDN博客_makefile中的subst

        隐含规则
        在我们使用Makefile 时,有一些我们会经常使用,而且使用频率非常高的东西,比如,我们编译C/C++的源程序为中间目标文件(Unix下是[.o]文件,Windows 下是[.obj]文件)。本章讲述的就是一些在Makefile 中的“隐含的”,早先约定了的,不需要我们再写出来的规则。
     “隐含规则”也就是一种惯例,make 会按照这种“惯例”心照不喧地来运行,那怕我们的Makefile 中没有书写这样的规则。例如,把[.c]文件编译成[.o]文件这一规则,你根本就不用写出来,make 会自动推导出这种规则,并生成我们需要的[.o]文件。
      “隐含规则”会使用一些我们系统变量,我们可以改变这些系统变量的值来定制隐含规则的运行时的参数。如系统变量“CFLAGS”可以控制编译时的编译器参数。
        我们还可以通过“模式规则”的方式写下自己的隐含规则。用“后缀规则”来定义隐含规则会有许多的限制。使用“模式规则”会更回得智能和清楚,但“后缀规则”可以用来保证我们Makefile 的兼容性。
      我们了解了“隐含规则”,可以让其为我们更好的服务,也会让我们知道一些“约定俗成”了的东西,而不至于使得我们在运行Makefile 时出现一些我们觉得莫名其妙的东西。当然,任何事物都是矛盾的,水能载舟,亦可覆舟,所以,有时候“隐含规则”也会给我们造成不小的麻烦。只有了解了它,我们才能更好地使用它。
     使用隐含规则
     如果要使用隐含规则生成你需要的目标,你所需要做的就是不要写出这个目标的规则。那么,make 会试图去自动推导产生这个目标的规则和命令,如果make 可以自动推导生成这个目标的规则和命令,那么这个行为就是隐含规则的自动推导。当然,隐含规则是make 事先约定好的一些东西。
    例如,我们有下面的一个Makefile:
    foo : foo.o bar.o
    cc –o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)
    我们可以注意到,这个Makefile 中并没有写下如何生成foo.o 和bar.o这两目标的规则和命令。因为make 的“隐含规则”功能会自动为我们自动去推导这两个目标的依赖目标和生成命令。
     make 会在自己的“隐含规则”库中寻找可以用的规则,如果找到,那么就会使用。如果找不到,那么就会报错。在上面的那个例子中,make 调用的隐含规则是,把[.o]的目标的依赖文件置成[.c],并使用C的编译命令“cc –c $(CFLAGS) [.c]”来生成[.o]的目标。也就是说,我们完全没有必要写下下面的两条规则:
    foo.o : foo.c
    cc –c foo.c $(CFLAGS)
    bar.o : bar.c
    cc –c bar.c $(CFLAGS)
     因为,这已经是“约定”好了的事了,make 和我们约定好了用C 编译器“cc”生成[.o]文件的规则,这就是隐含规则。
     当然,如果我们为[.o]文件书写了自己的规则,那么make 就不会自动推导并调用隐含规则,它会按照我们写好的规则忠实地执行。

     老式风格的"后缀规则"
     后缀规则是一个比较老式的定义隐含规则的方法。后缀规则会被模式规则逐步地取代。因为模式规则更强更清晰。为了和老版本的Makefile 兼容,GNU make 同样兼容于这些东西。后缀规则有两种方式:"双后缀"和"单后缀"。
       双后缀规则定义了一对后缀:目标文件的后缀和依赖目标(源文件)的后缀。如".c.o"相当于"%o : %c"。单后缀规则只定义一个后缀,也就是源文件的后缀。如".c"相当于"% : %.c"。
      后缀规则中所定义的后缀应该是make 所认识的,如果一个后缀是make 所认识的,那么这个规则就是单后缀规则,而如果两个连在一起的后缀都被make 所认识,那就是双后缀规则。

       例如:".c"和".o"都是make 所知道。因而,如果你定义了一个规则是".c.o"那么其就是双后缀规则,意义就是".c"是源文件的后缀,".o"是目标文件的后缀。如下示例:
    .c.o:
    $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
     后缀规则不允许任何的依赖文件,如果有依赖文件的话,那就不是后缀规则,那些后缀统统被认为是文件名,如:
    .c.o: foo.h
    $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
    这个例子,就是说,文件".c.o"依赖于文件"foo.h",而不是我们想要的这样:
     %.o: %.c foo.h
     $(CC) -c $(CFLAGS) $(CPPFLAGS) -o $@ $<
     后缀规则中,如果没有命令,那是毫无意义的。因为他也不会移去内建的隐含规则。

    举例

.c.obj:     //双后缀规则
    $(CC) -c $(SHUTUPFLAGS) $(CFLAGS) $<     //命令, $< 依赖目标的第一个文件,如果依赖目标采用模式表示,则$<为依赖目标的全部列表

gsf.obj:    gsf.c gsf.h gsf_dec.h gsf_enc.h gsf_ft.h gsf_indx.h
gsf_dec.obj:    gsf_dec.c gsf.h gsf_dec.h gsf_enc.h gsf_ft.h gsf_indx.h
gsf_enc.obj:    gsf_enc.c gsf.h gsf_dec.h gsf_enc.h gsf_ft.h gsf_indx.h
gsf_indx.obj:    gsf_indx.c gsf.h gsf_dec.h gsf_enc.h gsf_ft.h gsf_indx.h
gsf_info.obj:    gsf_indx.c gsf.h gsf_dec.h gsf_enc.h gsf_ft.h gsf_indx.h

//包含隐含规则

gsf.obj:gsf.c gsf.h gsf_dec.h gsf_enc.h gsf_ft.h gsf_indx.h

        $(CC) -c gsf.c $(SHUTUPFLAGS) $(CFLAGS) 

以上是关于nmake文件学习记录看《跟我一起写Makefile》的主要内容,如果未能解决你的问题,请参考以下文章

nmake文件学习记录看《跟我一起写Makefile》

跟我一起写 Makefile

跟我一起写一个chrome扩展程序

跟我一起写一个chrome扩展程序

拒绝某度文库,跟我一起用Python写个下载器

转载跟我一起学习VIM - vim插件