【问题标题】:Incorrect C Makefiles to generate library and main program?生成库和主程序的 C Makefile 不正确?
【发布时间】:2022-01-02 05:30:17
【问题描述】:

在 C 中有一个库和一个主测试驱动程序,但是虽然可以成功编译库,但主测试驱动程序不能。

目录结构如下:

qxu@xqiang-mac-1:~/test/test_makefile$ ll
total 0
drwxr-xr-x  3 qxu  staff   96 Nov 23 13:19 include
drwxr-xr-x  6 qxu  staff  192 Nov 23 13:31 print_ascii_tree
drwxr-xr-x  5 qxu  staff  160 Nov 23 13:33 test_main_driver

qxu@xqiang-mac-1:~/test/test_makefile$ ll include/
total 8
-rw-r--r--  1 qxu  staff  706 Nov 23 12:12 print_ascii_tree.h

qxu@xqiang-mac-1:~/test/test_makefile$ ll print_ascii_tree/
total 32
-rw-r--r--  1 qxu  staff   250 Nov 23 13:31 Makefile
-rw-r--r--  1 qxu  staff  9122 Nov 23 12:12 print_ascii_tree.c

qxu@xqiang-mac-1:~/test/test_makefile$ ll test_main_driver/
total 16
-rw-r--r--@ 1 qxu  staff  616 Nov 23 13:33 Makefile
-rw-r--r--@ 1 qxu  staff  918 Nov 23 11:51 main.c

这是库的生成文件:

qxu@xqiang-mac-1:~/test/test_makefile/print_ascii_tree$ cat Makefile 
AR = ar -rcs
RM = rm -rf
CC = gcc
CFLAGS = -I../include

libprint_ascii_tree.a: print_ascii_tree.o
    $(AR) libprint_ascii_tree.a print_ascii_tree.o

print_ascii_tree.o: print_ascii_tree.c 
    $(CC) $(CFLAGS) -c print_ascii_tree.c

clean:
    $(RM) *.o *.a

这个库可以顺利编译:

qxu@xqiang-mac-1:~/test/test_makefile/print_ascii_tree$ make
gcc -I../include -c print_ascii_tree.c
ar -rcs libprint_ascii_tree.a print_ascii_tree.o
qxu@xqiang-mac-1:~/test/test_makefile/print_ascii_tree$ ll
total 64
-rw-r--r--  1 qxu  staff   250 Nov 23 13:31 Makefile
-rw-r--r--  1 qxu  staff  7672 Nov 23 13:38 libprint_ascii_tree.a
-rw-r--r--  1 qxu  staff  9122 Nov 23 12:12 print_ascii_tree.c
-rw-r--r--  1 qxu  staff  7128 Nov 23 13:38 print_ascii_tree.o

这是测试驱动程序的 Makefile:

qxu@xqiang-mac-1:~/test/test_makefile/test_main_driver$ cat Makefile 
program_NAME := main.out

SRCS = main.c 
OBJS := ${SRCS:.c=.o}

CC = gcc
CFLAGS = -fsanitize=address -Wall -Wextra -g

program_INCLUDE_DIRS := ../include
program_LIBRARY_DIRS := ../print_ascii_tree
program_LIBRARIES := print_ascii_tree

CFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir))
LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir))
LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library))

LINK.c := $(CC) $(CFLAGS) $(LDFLAGS)

.PHONY: all

all: $(program_NAME)

$(program_NAME): $(OBJS)
    $(LINK.c) $(program_OBJS) -o $(program_NAME)

clean:
    rm -rf *.o *.out

这是错误:

qxu@xqiang-mac-1:~/test/test_makefile/test_main_driver$ make
gcc -fsanitize=address -Wall -Wextra -g -I../include   -c -o main.o main.c
gcc -fsanitize=address -Wall -Wextra -g -I../include -L../print_ascii_tree -lprint_ascii_tree  -o main.out
Undefined symbols for architecture x86_64:
  "_main", referenced from:
     implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [main.out] Error 1
qxu@xqiang-mac-1:~/test/test_makefile/test_main_driver$ ll
total 32
-rw-r--r--@ 1 qxu  staff   617 Nov 23 13:39 Makefile
-rw-r--r--@ 1 qxu  staff   908 Nov 23 13:40 main.c
-rw-r--r--  1 qxu  staff  6496 Nov 23 13:40 main.o

看起来main.o 已编译,但无法与库链接到主可执行文件中?

不确定 Makefile 出了什么问题。

附:这是main.c 中的内容:

qxu@xqiang-mac-1:~/test/test_makefile/test_main_driver$ cat main.c
#include "print_ascii_tree.h"

int main()
{
    printf("asdf\n");
    // A sample use of these functions.  Start with the empty tree
    // insert some stuff into it, and then delete it
    NodePtr root;
    root = NULL;

    make_empty(root);

    printf("\nAfter inserting key 10..\n");
    root = insert(10, root);
    print_ascii_tree(root);

    printf("\nAfter inserting key 5..\n");
    root = insert(5, root);
    print_ascii_tree(root);

    printf("\nAfter inserting key 15..\n");
    root = insert(15, root);
    print_ascii_tree(root);

    printf("\nAfter inserting keys 9, 13..\n");
    root = insert(9, root);
    root = insert(13, root);
    print_ascii_tree(root);

    printf("\nAfter inserting keys 2, 6, 12, 14, ..\n");
    root = insert(2, root);
    root = insert(6, root);
    root = insert(12, root);
    root = insert(14, root);

    print_ascii_tree(root);

    make_empty(root);
}

【问题讨论】:

  • 您是否记得在main.c 中定义了一个名为main 的函数?确保没有名为main 的前处理宏,因为这会弄乱定义。也许您应该发布您的完整代码,以便我们也可以检查main 的定义。
  • 您应该使用CFLAGS = -fsanitize=address -Wall -Wextra -g 并阅读GNU makeGCCGDBGNU binutils 的文档
  • @DavidGrayson 是的,我有一个。将更新帖子以反映 main.c 的内容。

标签: c makefile


【解决方案1】:

这里:

$(program_NAME): $(OBJS)
    $(LINK.c) $(program_OBJS) -o $(program_NAME)

您使用未定义的program_OBJS 变量。如果将其修复为$(OBJS)$^,则LINK.c 存在另一个问题。定义为:

LINK.c := $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)

这意味着生成的命令将首先具有库,然后是main.o

-lprint_ascii_tree main.o

链接器不会找到库中定义的main.o 中使用的符号。

我不确定您是否可以使用单独的 LINK.c 变量使其工作,但这应该可以工作:

$(program_NAME): $(OBJS)
    $(CC) $(CFLAGS) $(CPPFLAGS) $^ $(LDFLAGS) -o $@

【讨论】:

  • 感谢您发现此 Makefile 中的问题,danadam。我对 Makefile 不是特别熟悉,并将它从答案中复制到旧的 stackoverflow question,但没有意识到答案仍有待修复。
  • 另一个问题:有没有办法在主测试驱动程序目录中运行makemake clean,以便同时生成/清除其所有依赖项?我记得有这样一种方法,但无法将它放在我的头上。 :(
  • 这可能不是推荐的方式,但您可以在命令中添加for d in $(program_LIBRARY_DIRS); do make -C "$${d}"; done。清洁类似。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-10
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
  • 2012-06-28
  • 1970-01-01
相关资源
最近更新 更多