Jackdaw 发表于 2019-1-19 18:21:30

Makefile 项目管理(升级版)

本帖最后由 Jackdaw 于 2020-9-2 20:12 编辑

上次写了一篇《Makefile 项目管理》,感觉意犹未尽,现在重新写了一个新的

此次更新内容包括:
1. 文件分类存放
2. 自动生成依赖关系

依赖:
makedepf90

Makefile:
#!/bin/bash
# 设置文件路径
SRCDIR = src
OBJDIR = obj
MODDIR = mod
BINDIR = bin
# 文件
SRC    = floatPrecision.f90 GE_MPC.f90
SRC   := $(SRC) main.f90
OBJ    = $(SRC:.f90=.o)
# 增加前缀
SRCS= $(addprefix $(SRCDIR)/, $(SRC))
OBJS= $(addprefix $(OBJDIR)/, $(OBJ))
# 编译器相关设置
FC   = gfortran
FF   = -cpp -O0 -g -fbacktrace
DF   = -DDOUBLE_PRECISION
EXE    = myPro
# 所有目标
all: $(OBJDIR)/depend $(OBJS) binary
# 依赖关系
include $(OBJDIR)/depend
# 链接
binary: $(OBJS)
      $(FC) $(FF) $(DF) -J$(MODDIR) $(OBJS) -o $(BINDIR)/$(EXE)
# 编译
$(OBJS):
      $(FC) $(FF) $(DF) -J$(MODDIR) -c $< -o $@
# 检查路径,并生成依赖关系
.PONHY: $(OBJDIR)/depend
$(OBJDIR)/depend:   
      @if test -d $(SRCDIR); then echo "# directory "$(SRCDIR) "exists"; else mkdir $(SRCDIR); fi
      @if test -d $(OBJDIR); then echo "# directory "$(OBJDIR) "exists"; else mkdir $(OBJDIR); fi
      @if test -d $(MODDIR); then echo "# directory "$(MODDIR) "exists"; else mkdir $(MODDIR); fi
      @if test -d $(BINDIR); then echo "# directory "$(BINDIR) "exists"; else mkdir $(BINDIR); fi
      makedepf90 -b $(OBJDIR) $(SRCS) > $(OBJDIR)/depend            
# 清理工程    
.PONHY: clean
clean :      
      rm -rf $(OBJDIR)/depend $(MODDIR)/*.mod $(OBJS) $(BINDIR)/$(EXE)         
      





下面看看执行结果(测试代码见附件):







pasuka 发表于 2019-1-29 09:19:15

赞!
要是有个cmake的简易教程就完美了

Jackdaw 发表于 2019-1-29 13:59:04

pasuka 发表于 2019-1-29 09:19
赞!
要是有个cmake的简易教程就完美了

也有,以前写的,很简单的一个帖子
使用cmake管理Fortran项目(demo)

静待花开 发表于 2023-8-4 20:56:44

Jackdaw 发表于 2019-1-29 13:59
也有,以前写的,很简单的一个帖子
使用cmake管理Fortran项目(demo)

这个模板非常好,我正在好好学习。有个问题不明白,想请教楼主,第9行为何=号前面有:号呢?这表示什么呢?我在makefile的书写规则里查不到这个,希望楼主指点一下,非常感谢!

kyra 发表于 2023-8-4 21:22:09

静待花开 发表于 2023-8-4 20:56
这个模板非常好,我正在好好学习。有个问题不明白,想请教楼主,第9行为何=号前面有:号呢?这表示什么 ...

首先你需要理解,makefile文件并不是像编程语言一样按行执行的,make会一次性的把makefile读取完,并根据生成规则去执行(而不是按照文件顺序一行一行执行)。

所以,
a = text
a = next
这样写的话。a 的值会是整个makefile中最后一次的赋值(也就是next)。

而如果写成
a := text
a := next
的话,则 a 的值会是按照当前行的顺序而获得的值。

一般情况下,如果要重复对一个量赋值,第一次写 =,第二次及以后都写 :=

静待花开 发表于 2023-8-4 22:37:33

本帖最后由 静待花开 于 2023-8-5 11:13 编辑

kyra 发表于 2023-8-4 21:22
首先你需要理解,makefile文件并不是像编程语言一样按行执行的,make会一次性的把makefile读取完,并根据 ...
非常感谢版主回得这么快、这么详细。经过您的讲解,我理解了楼主这样处理 似乎就是为了 编译含有module这样的程序。这种处理 module的巧妙,令人佩服。因为我按照常规方法准备Makefile,make后总是提示找不到.mod文件,所以才找到了这个经典的贴子。
把楼主的文件down下来操作一遍,总是有问题,不能make成功。才发现makedepf90也是一个需要预先安装的程序,sudo apt install makedepf90。然后顺利编译成功。谢谢楼主提供这么好的一个Makefile模板。
打算在这个基础上再修改一下,不需要自己输入第8行、第9行的文件名,不知道可不可行。

静待花开 发表于 2023-8-6 10:35:39

kyra 发表于 2023-8-4 21:22
首先你需要理解,makefile文件并不是像编程语言一样按行执行的,make会一次性的把makefile读取完,并根据 ...

查了好多,没有见到解释 25行/28行 中的 -J 是表示什么,可否请版主指点下?非常感谢

kyra 发表于 2023-8-6 10:55:35

静待花开 发表于 2023-8-6 10:35
查了好多,没有见到解释 25行/28行 中的 -J 是表示什么,可否请版主指点下?非常感谢 ...

-J 不是 make 的语法哟,是 gfortran 的命令行参数。
表示指定 .mod 文件所在的路径。

可以在这里查看gfortran的帮助
https://gcc.gnu.org/onlinedocs/gfortran/
-J属于目录指定参数(类别)
https://gcc.gnu.org/onlinedocs/gfortran/Directory-Options.html

静待花开 发表于 2023-8-6 21:37:58

kyra 发表于 2023-8-6 10:55
-J 不是 make 的语法哟,是 gfortran 的命令行参数。
表示指定 .mod 文件所在的路径。



嗯嗯,明白了,:-handshake:-handshake非常非常感谢,我还得继续学习gfortran,也是刚接触 。

静待花开 发表于 2023-8-7 21:32:24

本帖最后由 静待花开 于 2023-8-8 15:56 编辑

kyra 发表于 2023-8-6 10:55
-J 不是 make 的语法哟,是 gfortran 的命令行参数。
表示指定 .mod 文件所在的路径。


这是我在楼主基础上修改后的。就是想做得更通用一点,不需要用户在makefile里面输入源代码文件名(如原makefile第8、第9行)。思路是:把module文件的后缀都改为.module,一个module写在一个.module文件中,并且文件名与module名称完全一样。但make之后,生成的*.mod文件除了输出到mod文件夹内,还输出在了makefile所在的目录(即与makefile放在一起),能编译成功,但多了这些.mod文件,还需要在删除。试了好多办法,实在想不到更好办法,想请版主看看是什么问题。楼主看到的话,也请指点一下。
下面是我改后makefile文件。
#!/bin/bash
# 设置文件路径
SRCDIR= src
OBJDIR= obj
MODDIR= mod
BINDIR= bin

# 文件
SRC      = $(wildcard $(SRCDIR)/*.f90)
OBJ      = $(addprefix $(OBJDIR)/, $(patsubst %.f90,%.o,$(notdir $(SRC))))

MODSRC   = $(wildcard $(SRCDIR)/*.module)
MODOBJ   = $(addprefix $(OBJDIR)/, $(patsubst %.module,%.o,$(notdir $(MODSRC))))

MOD      = $(addprefix $(MODDIR)/, $(patsubst %.module,%.mod,$(notdir $(MODSRC))))


# 编译器相关设置
FC   = gfortran
FF   = -cpp -O0 -g -fbacktrace
DF   = -DDOUBLE_PRECISION
EXE    = myPro

# 所有目标
all: $(OBJDIR)/depend binary

# 依赖关系
include $(OBJDIR)/depend


# 链接
binary: $(OBJ) $(MODOBJ)
    $(FC) $(FF) $(DF) -J$(MODDIR) $(OBJ) $(MODOBJ) -o $(BINDIR)/$(EXE)

# 编译
$(OBJ): $(SRC) $(MOD)
    $(FC) $(FF) $(DF) -J$(MODDIR) -c $< -o $@

$(OBJDIR)/%.o: $(SRCDIR)/%.module
    $(FC) -c -cpp -x f95 $< -o $@

$(MODDIR)/%.mod: $(SRCDIR)/%.module
    $(FC) -c -cpp -x f95 $< -o $@

# 检查路径,并生成依赖关系
.PONHY: $(OBJDIR)/depend
$(OBJDIR)/depend:   
    @if test -d $(SRCDIR); then echo "# directory "$(SRCDIR) "exists"; else mkdir $(SRCDIR); fi
    @if test -d $(OBJDIR); then echo "# directory "$(OBJDIR) "exists"; else mkdir $(OBJDIR); fi
    @if test -d $(MODDIR); then echo "# directory "$(MODDIR) "exists"; else mkdir $(MODDIR); fi
    @if test -d $(BINDIR); then echo "# directory "$(BINDIR) "exists"; else mkdir $(BINDIR); fi
    makedepf90 -b $(OBJDIR) $(SRCS) > $(OBJDIR)/depend      

clean-all:      
    rm -rf $(OBJDIR)/depend *.o *.mod $(MOD) $(MODOBJ) $(OBJ) $(BINDIR)/$(EXE)   


页: [1]
查看完整版本: Makefile 项目管理(升级版)