0

到现在为止,我一直在使用以下我为我的学校项目生成的生成文件:

我的生成文件

但是现在我有一个不同的情况:我应该为一个项目编译4个程序,而部分代码应该编译为.so,供4个程序使用。就像这里描述的:

我的项目的依赖项

1 - 所有应该编译为一个.so文件的部分,例如:

gcc -shared -fPIC src/file1.c src/file2.c src/file3.c -o libutils.so

3,4,5应该与这个.so文件一起编译和链接,例如:

gcc src/file4.c -L'pwd' lutils -o file4.out

对所有 3 个项目都采用相同的方式,并且对项目 2 进行更简单的编译。

我在网上、谷歌、你的网站等上徘徊,试图为这种情况找到解决方案,但没有任何运气。

已经见过像这样的解决方案: 解决方案示例 ,您可以在其中提供包含整个项目结构详细信息的 makefile。

我考虑将所有文件分成 4 个文件夹,位于主文件夹下方,并在 makefile 中创建一个循环,该循环将在每个循环中编译每个程序,并根据索引使用“if”语句进行不同的编译。但我没有运气,这似乎很复杂(也许有人可以向我展示一个这样的解决方案......)。

我想知道是否有一种方法可以使整个编译过程像当前文件一样通用和自动(可能少一点),

如果有办法,我想研究并发现它。

先感谢您!!!阿里

4

1 回答 1

1

由于您有一个绘制得很好的依赖树,因此您“只需”将其转换为Makefile.

你可能想从这个开始:

.PHONY: all

all: reloader.exe block_finder.exe formatter.exe printdb.exe

MODULES = reloader block_finder formatter printdb linked_list bitcoin file_handler
SRCS = $(MODULES:%=%.c)

reloader.exe block_finder.exe formatter.exe printdb.exe: libbitcoin_manager.so

reloader.exe: reloader.o
block_finder.exe: block_finder.o
formatter.exe: formatter.o
printdb.exe: printdb.o

libbitcoin_manager.so: linked_list.o bitcoin.o file_handler.o
    gcc -shared -fPIC $^ -o $@

%.exe: %.o
    gcc $< -L. -lbitcoin_manager -o $@

%.o: %.c
    gcc -c $< -o $@

%.d: %.c
    gcc -MM -MT $@ -MT $*.o -MF $@ $<

include $(SRCS:%.c=%.d)

因为图表中没有循环,所以Makefile. 相反,您将所有依赖文件放在冒号的左侧,将它们依赖的文件放在右侧。

您可能希望在变量中收集更多“对象”,例如要构建的程序、库中的模块等等。

我还使用了一种通用模式从头文件生成依赖项。所示方式只是其中一种方式。它使用带有“ .d”扩展名的文件来表示“依赖”。GCC 可以选择构建这些文件,它会扫描源代码并收集所有包含的头文件,即使是“堆叠的”。

例如,“ bitcoin.d”看起来像这样:

bitcoin.d bitcoin.o: bitcoin.c bitcoin.h linked_list.h definitions.h \
 file_handler.h

重新生成对源更改的依赖文件,它也是一个目标,而不仅仅是目标文件。


编辑:

首先,使用目录使 Makefiles 更加困难。我不喜欢这样的结构不仅是因为这个原因,还因为它们将明显属于彼此的头文件和实现文件分开。

无论如何,这是一个增强的Makefile

.PHONY: all

SRCDIR = src
INCDIR = include
BLDDIR = build

APPS = reloader block_finder formatter printdb
MODULES = reloader block_finder formatter printdb linked_list bitcoin file_handler
LIBNAME = bitcoin_manager
LIBMODULES = linked_list bitcoin file_handler

VPATH = $(SRCDIR)

SRCS = $(MODULES:%=%.c)
LIB = $(LIBNAME:%=lib%.so)
#win LIB = $(LIBNAME:%=%.lib)
EXES = $(APPS:%=%.exe)

all: $(BLDDIR) $(EXES)

$(BLDDIR):
    mkdir $@

$(LIB): $(LIBMODULES:%=$(BLDDIR)/%.o)
    gcc -shared -fPIC $^ -o $@

$(EXES): $(LIB)

$(EXES): %.exe: $(BLDDIR)/%.o
    gcc $< -L. -l$(LIBNAME) -o $@

$(BLDDIR)/%.o: %.c
    gcc -I$(INCDIR) -c $< -o $@

$(SRCDIR)/%.d: %.c
    gcc -I$(INCDIR) -MM -MT $@ -MT $(BLDDIR)/$*.o -MF $@ $<

include $(SRCS:%.c=$(SRCDIR)/%.d)

它使用更多变量来简化重命名和管理不断增长的库和应用程序。

一个重要的问题是使用VPATH. 这使得make在分配给它的路径列表中搜索源。确保您完全理解它,搜索文章和文档。很容易用错。

图案$(EXES): %.exe: $(BLDDIR)/%.o很好看。它由三部分组成,首先是目标列表,其次是具有单个目标及其源的通用模式。这意味着对于所有可执行文件,它们中的每一个都是从其目标文件构建的。

现在回答你的问题:

  1. 由新提案回答。我没有添加目录,而是使用VPATH.

  2. Make 停止不是因为 exe-from-o 模式错误,而是因为它没有找到构建所需目标文件的方法。新提案也解决了这个问题。想知道如果你删除旧提案中的这 4 个食谱会发生什么:你可以做实验,那就去做吧!

  3. 就像 user3629249 试图说的那样,这个点是当前的工作目录。你在你的 Makefile 中有它'pwd',我替换了它。这对 来说并不特殊make,它在所有主要操作系统中都很常见,包括 Windows。您可能知道..哪个指定父目录。

  4. 启动时make,它会读取该Makefile文件或任何给定文件。如果此文件包含include指令,则检查列出的文件是否需要重建。make即使你用-n! 在(重新)构建所有要包含的文件之后,它们最终被包含在内。现在make拥有所有配方并继续其“正常”工作。

于 2019-12-02T08:38:14.837 回答