生成库和主程序的 C Makefile 不正确?

Incorrect C Makefiles to generate library and main program?

有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

这是库的 makefile:

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 中有什么问题。

P.S。这是 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);
}

这里:

$(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 $@