【问题标题】:Compiling and linking subfolders using different Makefiles使用不同的 Makefile 编译和链接子文件夹
【发布时间】:2019-01-02 15:18:11
【问题描述】:

我在 C 中有一个客户端/服务器应用程序。服务器有自己的文件夹 dserver,客户端 dclient 也是如此。使用它们两个包含实用程序函数的文件,我创建了另一个目录,与之前的目录处于同一级别,命名为common

我的想法是在每个子文件夹中创建每个Makefile(一个在dserver,一个在dclient,另一个在common),然后一个Makefile在主目录中运行另一个@ 987654330@ 看起来像:

all:
    +$(MAKE) -C common
    +$(MAKE) -C dserver
    +$(MAKE) -C dclient

第一个问题是common/Makefile 不应该创建可执行文件,而只创建为客户端和服务器创建可执行文件所需的目标文件。在我的情况下是:

CXX = gcc

SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR=$(SOURCEDIR)/obj

OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))

# ADD MORE WARNINGS!
WARNING := -Wall -Wextra

$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
    $(CXX) $(WARNING) -MMD -MP -c $< -o $@

$(OBJDIR):
    mkdir -p $(OBJDIR)

我的问题是它正在创建OBJDIR指定的对象目录,而不是*.o指定的对象文件:应该怎么做?

其次,在客户端和服务器Makefiles 中,我都应该在common 中包含文件的路径,然后在common 的编译结果中引用目标文件来构建可执行文件。因此以dserver/Makefile 为例,我添加了INC_PATH = -I../common/ 行并在编译中将其引用为$(CXX) $(WARNING) -MMD -MP -c $(INC_PATH) $&lt; -o $@。但是在代码中我必须做#include "../common/utilities.h"

有没有办法在 Makefile 中包含路径,以便在代码中只允许这样做:#include "utilities.h"

另外,假设common 有自己的对象目录,其中包含客户端和服务器所需的对象文件,如何构建,例如服务器可执行文件引用common 目录中的对象文件和那些具体并包含在server 目录中?

dserver/Makefile 类似于(dclient/Makefile 具有相同的结构):

CXX = gcc

INC_PATH = -I../common/

SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR=./obj

OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))

# ADD MORE WARNINGS!
WARNING := -Wall -Wextra

# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean

# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: server

clean:
    $(RM) $(OBJECTS) $(DEPENDS) server

# Linking the executable from the object files
# $^   # "src.c src.h" (all prerequisites)
../server: $(OBJECTS)
    $(CXX) $(WARNING) $(INC_PATH) $^ -o $@
    #$(CXX) $(WARNING) $(CXXFLAGS) $(INC_PATH) $^ -o $@ $(LIBS)

-include $(DEPENDS)

$(OBJDIR):
    mkdir -p $(OBJDIR)

$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
    $(CXX) $(WARNING) -MMD -MP -c $(INC_PATH) $< -o $@

【问题讨论】:

标签: c makefile compilation


【解决方案1】:

您没有为在“通用”Makefile 中构建对象指定任何规则 - 这是您拥有的唯一规则。

$(OBJDIR):
    mkdir -p $(OBJDIR)

您想在此之前设置一条规则,以便所有人都能使用它来构建对象,可能类似于以下内容:

all: $(OBJDIR) $(OBJECTS)

它必须在原始规则之前,就好像你没有指定要构建的内容一样,make 会执行它找到的第一条规则。

使用-I../common/ 在其他目录中包含“common”中的头文件应该可以正常工作。

使用“common”中的对象应该只是将它们添加到对象列表中的一种情况,即:

COMMON_OBJECTS=../common/obj/utilities.o

../server: $(OBJECTS) $(COMMON_OBJECTS)

或者将它们内置到库中,这样您就不需要知道有哪些目标文件。

另外值得注意的是,$(CXX) 是用于存储 C++ 编译器的变量 - 用于构建您想要使用 $(CC)$(CFLAGS) 的 C 编译器。

【讨论】:

  • all: $(OBJDIR) $(OBJECTS) 在并行构建中中断。稳健的方法是让目标文件仅按顺序依赖于它们的目录。例如%.o : %.cc | $$(@D)(需要.SECONDEXPANSION)。
  • ../server: $(OBJECTS) $(COMMON_OBJECTS) 不起作用:似乎链接不正确:错误是undefined reference to FunctionInCommonFile
  • 尽管common/Makefile 中的规则你是对的
  • @FrancescoBoi 表示您错过了常见的一个(或多个)目标文件,或者您尚未编写一些代码
猜你喜欢
  • 1970-01-01
  • 2012-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多