You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CUnit测试时出现'main'重定义错误的求助

问题描述

执行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;
}
问题原因

C语言规定:一个可执行程序必须且只能有一个main函数,它是操作系统启动程序时的唯一入口点。你的错误源于:

  • 执行make后,主程序的motcache.c被编译成motcache.o,其中包含一个main函数
  • 执行make test时,编译测试文件生成test_errors.o、test_file_handling.o,每个都包含自己的main
  • 链接测试程序时用了*.o,把所有目标文件(包括带main的motcache.o)都包含进来,导致链接器发现多个main定义,无法确定入口,因此报错。
解决方案

方法1:修改Makefile,分开主程序和测试的目标文件

调整Makefile,将主程序和测试的目标文件存放在不同目录,避免链接时混合。修改后的Makefile如下:

CC = gcc
OPTIONS = -Wall -Wextra
EXE = motcache
SRC_DIR = src
TESTS_DIR = test
OBJ_DIR = obj
TEST_OBJ_DIR = test_obj

all : start

# 编译主程序源码到obj目录
compile :
    mkdir -p $(OBJ_DIR)
    $(CC) $(OPTIONS) -c $(SRC_DIR)/*.c
    mv *.o $(OBJ_DIR)/

# 链接生成主程序
link: compile
    $(CC) $(OBJ_DIR)/*.o -o $(EXE)

# 编译测试代码到test_obj目录
compile_test :
    mkdir -p $(TEST_OBJ_DIR)
    $(CC) $(OPTIONS) -c $(TESTS_DIR)/*.c
    mv *.o $(TEST_OBJ_DIR)/

# 链接测试程序:只包含主程序中除motcache.o(带main)的文件,加上测试文件
link_test : compile_test compile
    SRC_OBJS = $(filter-out $(OBJ_DIR)/motcache.o, $(OBJ_DIR)/*.o)
    $(CC) $(OPTIONS) $(SRC_OBJS) $(TEST_OBJ_DIR)/*.o -o cunit_tests -lcunit

run_test: link_test
    ./cunit_tests

clean:
    rm -rf $(OBJ_DIR) $(TEST_OBJ_DIR)
    rm -f $(EXE) cunit_tests

start: link
    ./$(EXE)

方法2:每个测试文件单独编译为可执行程序

如果不需要合并所有测试到一个可执行文件,可以修改Makefile,为每个测试文件生成单独的测试程序:

CC = gcc
OPTIONS = -Wall -Wextra
EXE = motcache
SRC_DIR = src
TESTS_DIR = test

all : start

compile :
    $(CC) $(OPTIONS) -c $(SRC_DIR)/*.c

link: compile
    $(CC) *.o -o $(EXE)

# 编译所有测试文件为单独的可执行
test:
    for test_file in $(TESTS_DIR)/*.c; do \
        test_name=$$(basename $$test_file .c); \
        # 编译测试文件+主程序中除motcache.o的目标文件
        $(CC) $(OPTIONS) $(filter-out motcache.o, *.o) $$test_file -o $$test_name -lcunit; \
        ./$$test_name; \
        rm $$test_name; \
    done

clean:
    rm -f $(EXE) *.o cunit_tests

start: link
    ./$(EXE)

关键注意事项

  • 测试程序不需要包含主程序的motcache.o,因为测试的是业务逻辑函数(比如open_file),不需要主程序的入口
  • 始终确保每个可执行程序只有一个main函数,这是C程序的基本规则

内容的提问来源于stack exchange,提问作者TheGunner422

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 04:25:01