c - 如何找到源代码的依赖关系?

标签 c gcc makefile gnu-make gnu

假设我有一个简单的c库项目,布局如下

- src/
      - square_root.c
      - log.c
      - power.c
      - newton_method.c
- include/
      - square_root.h
      - log.h
      - power.h
      - newton_method.h

现在,我想创建一个简单的程序(main.c)来调用 square_root()

# main.c
# include "square_root.h" 
int main()
{
  printf("%f\n", square_root(4.0));
  return 0;
}

要编译 main.c,必须将 newton_method.c 包含到构建中。

gcc main.c src/square_root.c src/newton_method.c -o main

在本例中,newton_method.c 是 square_root.c 的依赖项。 如果库很大或编写得不好,那么查找源代码的依赖关系就会变得很困难。 当然,可以在构建过程中包含所有 *.c,但这会使构建过程缓慢且笨拙。

我试过了

gcc -H -MM -M main.c

但它只给了我 *.h 而不是 *.c

是否有任何工具可以查找源代码的依赖关系?

最佳答案

解决方案

执行此操作的标准方法是此 paper 中描述的方法。由 Paul Smith(GNU Make 的当前维护者)编写。此方法使用 GCC 选项 -MMD -MP -MF -MT 来检测每个目标文件 *.o 的依赖关系。然后,它创建依赖项文件 *.d 并用构建每个对象的规则填充它们,包括所有必要的依赖项(源和 header )。引用这个page如果您想了解有关 GCC 选项的更多信息。对于您的情况,以下 makefile 应该足够了:

SRCS := main.c square_root.c newton_method.c
BIN := main

SRCS := $(SRCS:%=src/%)
OBJS := $(SRCS:src/%.c=obj/%.o)
DEPS := $(OBJS:%.o=%.d)

all: $(BIN)

$(BIN): $(OBJS)
    gcc -o $@ $^

obj/%.o: src/%.c obj/%.d
    gcc -c -I include -MMD -MP -MF $(patsubst obj/%.o,obj/%.d,$@) -MT $@ -o $@ $<

$(DEPS):
-include $(DEPS)

关于 makefile 的观察:

  • 您必须将 makefile 放在根目录中。
  • 当您将代码复制到 makefile 时,请注意缩进部分(每条规则的说明)。每个命令行必须以 TAB 字符开头,而不是空格。
  • 我假设所有源文件*.c都在目录src/中,并且所有头文件*.h位于目录 include/ 中。
  • 编译器会将所有目标文件*.o和依赖文件*.d放在目录obj/中。我假设该目录已经存在。
  • 您可以通过修改变量 SRCS 来选择涉及的源文件,但只有其中一个可以包含 main() 函数。
  • 您可以通过修改变量BIN来选择可执行文件的名称。
  • 可执行文件将在根目录中创建。

测试设置

我尝试根据您所说的内容重现您的场景。为了测试 makefile,我使用了以下源文件和头文件。

src/main.c

#include <stdio.h>
#include "square_root.h"
int main()
{
    printf("%f\n", square_root(4.0));
    return 0;
}

include/square_root.h

float square_root(float x);

src/square_root.c

#include "square_root.h"
#include "newton_method.h"
float square_root(float x)
{
    return newton_method(x);
}

include/newton_method.h

float newton_method(float x);

src/newton_method.c

#include "newton_method.h"
float newton_method(float x)
{
    return x;
}

依赖文件

下面是编译器创建的依赖文件。您将看到每个文件都有一个规则来构建目标文件,并以所有依赖项(源和 header )作为先决条件。编译器还为除主源文件之外的每个依赖项添加一个目标,导致每个依赖项不依赖任何内容。如果您删除头文件而不更新 makefile 来匹配,这些虚拟规则可以解决 GNU Make 给出的错误。所有这一切都是自动完成的。很酷吧? :)

ma​​in.d

obj/main.o: src/main.c include/square_root.h

include/square_root.h:

square_root.d

obj/square_root.o: src/square_root.c include/square_root.h \
 include/newton_method.h

include/square_root.h:

include/newton_method.h:

newton_method.d

obj/newton_method.o: src/newton_method.c include/newton_method.h

include/newton_method.h:

关于c - 如何找到源代码的依赖关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68766826/

相关文章:

c - 为什么我的结构接收的是整数值(字符)而不是指针(字符串)?

c - 无需指定 'lib' 前缀即可在 gcc 中链接静态库

c - __libc_start_main 中发生了什么?

windows - 在 cygwin/msys bash 下使用 `pkg-config` 作为命令行参数

makefile - POSIX 可以从程序输出中设置一个变量吗?

c++ - 将 asm 指令编码为操作码

c - 对于所有数据类型,所有数据指针在一个平台中的大小是否相同?

c - 关于c语言的一道题

linux - 为 ARM 编译 Linux 内核 3.2 时出错

android-ndk - 如何使用Android.mk为不同平台指定不同的CFLAGS