【问题标题】:How to properly prepare makefile for bigger project?如何为更大的项目正确准备makefile?
【发布时间】:2021-01-11 16:38:27
【问题描述】:

我在编译和链接我的项目与目录组织时遇到问题,如下所示。

/project
|
|____/Components        (header files and source codes of all components)
|    |
|    |____/X            (header files and source codes of component)
|         |
|         |____/src     (source codes)
|         |
|         |____/include (header files)
|
|
|____/make              
|    | 
|    |____-Makefile     (Makefile)
|    |____-source.inc   (list of directories with header files)
|    |____-source.list  (list of every source file, .c and .cpp)
|
|____-main.c            (main source file)

当我在 cmd 中运行 make 时,我得到了这个错误:

make: *** No rule to make target '../build/obj/main.o', needed by '../build/bin/app'.  Stop.

保持这个目录组织对我来说很重要。

这是我的 Makefile

OUTDIR = ../build/
OBJDIR = $(OUTDIR)obj/
BINDIR = $(OUTDIR)bin/

LD = g++

APP = app

INC_DIRS = $(shell cat source.inc)

CFLAGS = -g0
CXXFLAGS = -g0 -Wall
LDFLAGS = -g0

COMPILE.c = $(BUILD_VERBOSE)$(CXX) $(CFLAGS) $(addprefix -I, $(INC_DIRS)) -c $< -o $@
COMPILE.cc = $(BUILD_VERBOSE)$(CXX) $(CXXFLAGS) $(addprefix -I, $(INC_DIRS)) -c $< -o $@

SRCS = $(shell egrep .[ccpp]$$ source.list)
OBJS = $(patsubst %,$(OBJDIR)%.o,$(basename $(notdir $(SRCS))))

$(BINDIR)$(APP): prep_dirs $(OBJS)
    @printf "\nBuilding Project $@\n"
    $(LD) $(LDFLAGS) $(OBJS) -o $@

$(OBJDIR)%.o: %.c
    @printf "\nCompiling: $<\n"
    $(COMPILE.c)
    $(POSTCOMPILE)

$(OBJDIR)%.o: %.cpp
    @printf "\nCompiling: $<\n"
    $(COMPILE.cc)
    $(POSTCOMPILE)

prep_dirs:
    $(BUILD_VERBOSE)mkdir -p $(OUTDIR)
    $(BUILD_VERBOSE)mkdir -p $(OBJDIR)
    $(BUILD_VERBOSE)mkdir -p $(BINDIR)

.PHONY: clean
clean:
    @printf "Cleaning executables...\n"
    $(BUILD_VERBOSE)rm -rf $(BINDIR)*.exe

.PHONY: cleanall
cleanall:
    @printf "Cleaning all objects...\n"
    $(BUILD_VERBOSE)rm -rf $(OUTDIR)

source.inc 和 source.list

source.inc
../Components/X/include

source.list
../Components/X/src/some_source.c
../main.c

你能告诉我我做错了什么吗?如何修复它并将 main.c 留在同一个地方?

【问题讨论】:

  • 我个人停止编写 makefile 以支持更高级别的构建系统,例如 cmake。更好的选择
  • “如何为更大的项目正确准备 makefile?” - 不这样做。对小型项目使用手动编写的 makefile,而不是大型项目。
  • 您是否考虑过使用其他构建自动化系统,例如ninja
  • 当源文件和/或目标文件不在当前目录中时,总是很难正确编写 Makefile。在您的情况下,make 不知道 ../main.c 应该是 ../build/obj/main.o 的源,并且找不到可以从现有源文件构建 .o 文件的规则。 some_source.c 也是如此。也许VPATHvpath 可以提供帮助。您必须将..../Components/X/src 指定为要搜索的目录。如果您在不同的源目录中有同名的文件,这可能会导致歧义。
  • @BasileStarynkevitch Ninja 旨在供更高级别的构建系统或生成器使用。用ninja 替换make 在这里可能没有多大帮助。见ninja-build.org

标签: c++ c makefile gnu-make


【解决方案1】:

一般来说: 不确定您的问题到底是什么,但这就是我所做的。该项目有一个单一的全局对象目录 (OBJDIR)。每个源目录都有自己的 Makefile,如下所示:

# list of sources in *this* directory
CCSRC = a.cc b.cc etc 
OBJS := $(addsuffix .o,  $(CCSRC))
VPATH = $(OBJDIR)
 .SUFFIXES: .cc .o
 .cc.o:
    $(CXX) $(CFLAGS) $< -o $(OBJDIR)/$@

项目顶层有一个 Makefile,它只是简单地更改到每个 src 目录并在该目录中运行 make:

include $(PROJ_HOME)/top.mk

# this allows sub-makes to find out if they have been invoked from this
# top-level make, or from a local make (from emacs in a source file directory,
# for example).
CALLED_FROM_TOP = true
export CALLED_FROM_TOP
    
all :
        cd dir1/src;          $(MAKE)
        cd dir2/rtv;          $(MAKE) debug=$(debug) etc

'top.mk' 包括全局定义、导出等。

这是一项艰苦的工作,但比我所知道的任何构建系统都能为您提供无限更好的细粒度控制。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-03
    相关资源
    最近更新 更多