我不熟悉使用 CUnit 和编写 C 程序。当我运行
make
然后 make test
时,我打印了这个错误:
/usr/bin/ld: test_errors.o: in function 'main':
test_errors.c:(.text+0x35): multiple definition of `main'; motcache.o:motcache.c:(.text+0x0): first defined here
/usr/bin/ld: test_file_handling.o: in function `main':
test_file_handling.c:(.text+0x96): multiple definition of `main'; motcache.o:motcache.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
make: *** [Makefile:21: link_test] Error 1
我的 Makefile 中有这个:
CC = gcc
OPTIONS = -Wall -Wextra
EXE = motcache
SRC_DIR = src
TESTS_DIR = test
all : start
compile :
$(CC) $(OPTIONS) -c $(SRC_DIR)/*.c
test: run_test
link: compile
$(CC) *.o -o $(EXE)
compile_test :
$(CC) $(OPTIONS) -c $(TESTS_DIR)/*.c
link_test : compile_test
$(CC) $(OPTIONS) *.o -o cunit_tests -lcunit
run_test: link_test
./cunit_tests
clean:
rm -f $(EXE) *.o cunit_tests
start: link
./$(EXE)
这是我的
test_file_handling.c
测试一个简单地打开文件的功能:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include "CUnit/CUnit.h"
#include "CUnit/Basic.h"
#include "../src/file_handling.h"
void test_open_file_success(void){
char *argv[] = {"./motcache", "mandoline.txt"};
FILE *fptr = open_file(argv);
CU_ASSERT_PTR_NOT_NULL(fptr);
fclose(fptr);
}
int main(){
CU_initialize_registry();
CU_pSuite suite = CU_add_suite("Ouverture de fichiers", NULL, NULL);
CU_add_test(suite, "Test d'ouverture de fichier avec succès", test_open_file_success);
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
CU_cleanup_registry();
return 0;
}
这是我的主要文件
motcache.c
:
#include <stdio.h>
#include "motcache.h"
#include "errors.h"
#include "file_handling.h"
int main(){
return 0;
}
我正在努力解决这个问题,因为我还在努力理解。我的每个功能中都不允许有
main
方法吗?如果方法名称不同,我的代码可以正常工作并且测试也可以正常工作。我很乐意在这个问题上接受任何建议或帮助。谢谢
给定:make: *** [Makefile:21: link_test] 错误 1
Makefile 中的第 21 行试图合并所有 *.o 文件,其中定义了两次 main() 函数。
21 $(CC) $(OPTIONS) *.o -o cunit_tests -lcunit
祝你好运
我正在努力解决这个问题,因为我还在努力理解。难道我的每个函数都不允许有
方法吗?main
C 没有方法,只有函数。 C 源文件是一个组织单元,但它们并不对应于 C++ 或 Java 中称为“方法”的任何东西,更不用说“类”了。特别是,它们不为函数或变量建立名称空间。 C 对于“普通标识符”只有一个全局命名空间,其中包括函数名和变量名等。
所以虽然是的,你可以在多个文件中有
main()
功能,你不能在同一个 program中有多个
main()
功能。因此,如果您有两个目标文件,每个目标文件都是从包含 main()
函数的源文件构建的,则不能将它们链接在一起。而这正是你想要做的。
也许你认为你正在构建程序
cunit_tests
仅来自 $(TESTS_DIR)/
中的源。我怀疑如果测试实际上是为了进行任何有用的测试,那是不可行的,但无论如何,这不是您编写的规则所产生的。所有目标文件都在顶级目录中构建,然后所有目标文件都由链接命令中的 *.o
glob 拾取。
部分问题是您编写的 makefile 很像程序程序。如果那是你想要的,那么直接在 shell 脚本中编写会更灵活。您将放弃使
make
成为如此长寿和广泛使用的工具的所有功能,但无论如何您现在实际上并没有使用任何这些功能。 shell脚本是人们以前使用的make
.
或者您可以通过以下方式发挥
make
的优势:
这也将使您受益于
make
的一些便利功能,尤其是其内置规则。这可能看起来像这样:
# Prefer conventional names for flags variables
CFLAGS = -Wall -Wextra
EXE = motcache
TEST_EXE = cunit_tests
SRC_DIR = src
TESTS_DIR = test
# All object files contributing to the primary executable only:
EXE_OBJS = $(SRC_DIR)/motcache.o ... and maybe others ...
# All object files contributing to the tests only:
TEST_OBJS = $(TESTS_DIR)/test_file_handling.o ... and probably others ...
# All object files contributing to both the primary executable and the tests
SHARED_OBJS = .. probably some $(SRC_DIR)/foo.o ...
all: $(EXE)
$(EXE): $(SHARED_OBJS) $(EXE_OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
$(TEST_EXE): $(SHARED_OBJS) $(TEST_OBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ -lcunit
run_test: $(TEST_EXE)
./$(TEST_EXE)
clean:
rm -f $(TEST_EXE) $(EXE) $(TEST_OBJS) $(SHARED_OBJS) $(OBJS)
.PHONY: all clean run_test
您可以适当地填写
*_OBJS
变量的值。至少在您更熟悉 make
之前,请按照示例并将目标文件指定为与其相应源位于相同目录中的目标文件。
如果您正在构建多个单独的测试可执行文件,那么您可能想要稍微修改一下,但这留作练习。
总的来说,这让你:
make
s 内置规则从 .c 源文件构建目标文件更不用说,通往实际工作构建的非常清晰的路径。