【问题标题】:Substitution reference with .cpp and .c files [closed].cpp 和 .c 文件的替换参考 [关闭]
【发布时间】:2016-06-29 02:35:25
【问题描述】:

我知道有很多关于将 .cpp 和 .c 文件混合到一个 makefile 中的问题,但我还没有看到混合替换引用的问题得到解决。我遇到了问题。

我的makefile是基于this answer的结构:

LIB=mylib.so
CPPSRCS += hello.cpp
CSRCS += goodbye.c

OBJS = $(CSRCS:.c=.o) $(CPPSRCS:.cpp=.o)

# Separate rules for .cpp and .c files, link together to form library.
# All pretty standard stuff and I am sure it will work if we goodbye.o and    
# hello.o are present.

这不起作用,我得到了旧的没有规则来制造目标错误。我究竟做错了什么?如何将两种类型的文件的替换引用转换为一个变量?

【问题讨论】:

  • 你得到的错误信息是什么?
  • 您在该 makefile 中没有任何目标 - 您预期会发生什么?
  • @Toby Speight 抱歉不清楚,我的真实 makefile 中确实有 .cpp 和 .c 文件的目标和不同的规则。这只是解决核心问题的一个玩具示例——无法从 .cpp 和 .c 文件正确生成 .o(从一个文件生成很简单)。

标签: c++ c makefile


【解决方案1】:

为了使makefile 同时适用于 C 和 C++,您需要为每种语言设置单独的规则 - 尽管有些规则是相同的。

另一个问题是链接器。仅 C 的项目将使用一个链接器,而不是另一个。

我将我的 makefile 转储到这里(来自this project)。

从这个例子可以看出,有两种不同的构建规则,一种用于使用 C 文件创建的对象,另一种用于使用 C++ 创建的对象。当第一个失败时,会尝试第二个,因此可以共享对象列表。

另外,您可能会注意到 C++ 规则有这一行 $(eval CCL = $(CPP)),它将链接器变量 (CCL) 设置为使用 C++ 的项目中的 C++ 链接器。这样,在调用构建规则时,它会使用正确的链接器。

另一件需要关注的是这段代码处理列表和扩展替换的方式。请注意foreachaddsuffixbasename 函数的使用...这显然比您建议的$(CSRCS:.c=.o) 更复杂。

我建议您添加一个显示 make 变量的规则,这样您就可以调试任何误入歧途的东西(参见演示),这是学习和解决问题的好方法。

关于makefile我在这里粘贴的几句警告......

它适用于 C 和 C++(混合)项目,几乎是“即插即用”,但您必须更改文件夹名称和目标文件以适应您的文件夹结构。

另外,请注意它会删除整个项目如果您将临时文件夹定义为项目文件夹(定义为tmp 是有原因的,因为它使清理变得非常容易)。

将来我可能会对其进行更新,以便自动添加任何 src 子文件夹,但目前我需要额外的控制来排除某些文件夹。

这个makefile主要是一个懒惰的工作......我讨厌一直更新makefile,所以我有一个低成本的makefile,它主要计算它自己的一切......除非我改变项目的文件夹结构或需要不同的图书馆。

NAME=demo

OUT_ROOT=./tmp
TMP_ROOT=./tmp
SRC_ROOT=.

SRC_EXTRA_FOLDERS=src src/http

LIBS=-pthread -lssl -lcrypto
INCLUDE=/usr/local/include

CC=@gcc
CPP=@g++
DB=@lldb
OPTIMIZATION=O3

#auto computed values
BIN = $(OUT_ROOT)/$(NAME)
SRCDIR = $(SRC_ROOT) $(foreach dir, $(SRC_EXTRA_FOLDERS), $(addsuffix /,$(basename $(SRC_ROOT)))$(dir))
SRC = $(foreach dir, $(SRCDIR), $(wildcard $(addsuffix /, $(basename $(dir)))*.c*))
BUILDTREE =$(foreach dir, $(SRCDIR), $(addsuffix /, $(basename $(TMP_ROOT)))$(basename $(dir)))
OBJS = $(foreach source, $(SRC), $(addprefix $(TMP_ROOT)/, $(addsuffix .o, $(basename $(source)))))
CCL = $(CC)

# the C flags
CFLAGS=-Wall -g -$(OPTIMIZATION) -std=c11 $(foreach dir,$(INCLUDE),$(addprefix -I, $(dir))) $(foreach dir,$(SRCDIR),$(addprefix -I, $(dir)))
CPPFLAGS= -Wall -$(OPTIMIZATION) -std=c++11 $(foreach dir,$(INCLUDE),$(addprefix -I, $(dir))) $(foreach dir,$(SRCDIR),$(addprefix -I, $(dir)))

$(NAME): build

build: $(OBJS)
    $(CCL) -o $(BIN) $^ -$(OPTIMIZATION) $(LIBS)

$(TMP_ROOT)/%.o: %.c
    $(CC) -o $@ -c $^ $(CFLAGS)

$(TMP_ROOT)/%.o: %.cpp
    $(CPP) -o $@ -c $^ $(CPPFLAGS)
    $(eval CCL = $(CPP))

clean:
    -@rm $(BIN)
    -@rm -R $(TMP_ROOT)
    -@mkdir -p $(BUILDTREE)

execute:
    @$(BIN)

run: | clean build execute

db: | clean build
    $(DB) $(BIN)

vars:
    @echo "BIN: $(BIN)"
    @echo ""
    @echo "SRCDIR: $(SRCDIR)"
    @echo ""
    @echo "SRC: $(SRC)"
    @echo ""
    @echo "BUILDTREE: $(BUILDTREE)"
    @echo ""
    @echo "OBJS: $(OBJS)"
    @echo ""
    @echo "CFLAGS: $(CFLAGS)"
    @echo ""
    @echo "CPPFLAGS: $(CPPFLAGS)"

按照 Toby Speight 的建议,我添加了管道符号 (|) 以将先决条件标记为已订购,以供所有并发人员使用。

【讨论】:

  • "Here's my makefile" 对 OP 没有太多的教育价值,谁会从 why 你的作品中受益更多,而你的作品却没有。请edit你的回答澄清原件有什么问题以及你做了什么来解决它。
  • 顺便说一句,我注意到规则 run: clean build execute 的目标不依赖于顺序,因此多线程 make 可能会在 clean 目标完成之前启动 execute 目标...跨度>
  • @TobySpeight,感谢您的意见。我没有注意到依赖部分,我会尽快编辑。至于解释,我经常将makefile 视为项目的先决条件,例如编译器,拥有应该做的工作,知道它为什么工作很好但并不重要......但你也是对的。我将添加几句话来说明为什么这允许 C++ 和 C 混合。但是,考虑到没有发布错误数据,我怀疑我会解释 OP 的 makefile 可能存在的问题。
  • @Myst foreach、basename、addsuffix 的组合正是我想要的......谢谢!
猜你喜欢
  • 1970-01-01
  • 2014-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-09
相关资源
最近更新 更多