ROS服务端/客户端编译报错:multiple definition of `main' 求助
Ubuntu 20.04、cmake 3.26.0-rc4环境下,编译带边缘检测类的ROS Service服务端/客户端时,出现multiple definition of 'main'错误。已将main函数分别放在不同.cpp文件中,怀疑CMakeLists.txt配置有误。
报错信息
/usr/bin/ld:
CMakeFiles/TARGET_NAME.dir/src/edge_srv_server_node.cpp.o:
in functionmain':edge_srv_server_node.cpp: (.text.startup+0x0): multiple definition ofmain';
CMakeFiles/TARGET_NAME.dir/src/edge_srv_client_node.cpp.o:
edge_srv_client_node.cpp:(.text.startup+0x0): first defined here
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/TARGET_NAME.dir/build.make:214:
~/catkin_ws/devel/.private/edge_detection/lib/libTARGET_NAME.so]
Error 1
make[1]: *** [CMakeFiles/Makefile2:1295:
CMakeFiles/TARGET_NAME.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
make: *** [Makefile:146: all] Error 2
当前CMakeLists.txt内容
cmake_minimum_required(VERSION 3.9.1) ######################################################################################################################## # Metadata ######################################################################################################################## # Read the package manifest. file(READ "${CMAKE_CURRENT_SOURCE_DIR}/package.xml" package_xml_str) # Extract project name. if(NOT package_xml_str MATCHES "<name>([A-Za-z0-9_]+)</name>") message(FATAL_ERROR "Could not parse project name from package manifest (aborting)") else() set(extracted_name ${CMAKE_MATCH_1}) endif() # Extract project version. if(NOT package_xml_str MATCHES "<version>([0-9]+.[0-9]+.[0-9]+)</version>") message(FATAL_ERROR "Could not parse project version from package manifest (aborting)") else() set(extracted_version ${CMAKE_MATCH_1}) endif() ######################################################################################################################## # CMake project ######################################################################################################################## project(${extracted_name} VERSION ${extracted_version}) ## Compile as C++11, supported in ROS Kinetic and newer add_compile_options(-std=c++11) find_package( OpenCV REQUIRED ) include_directories( ${OpenCV_INCLUDE_DIRS} ) find_package(catkin REQUIRED COMPONENTS roscpp rospy message_generation std_msgs geometry_msgs sensor_msgs ) ################################################ ## Declare ROS messages, services and actions ## ################################################ ## Generate services in the 'srv' folder add_service_files( FILES DetectEdges.srv ) ## Generate added messages and services with any dependencies listed here generate_messages( DEPENDENCIES std_msgs geometry_msgs sensor_msgs ) ################################### ## catkin specific configuration ## ################################### catkin_package( INCLUDE_DIRS include LIBRARIES edge_detection CATKIN_DEPENDS geometry_msgs std_msgs message_runtime # DEPENDS # system_lib ) ########### ## Build ## ########### include_directories( include ${catkin_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} ) file(GLOB_RECURSE CPP_FILES ${PROJECT_SOURCE_DIR}/src/*.cpp) set(SOURCES ${CPP_FILES}) add_library(TARGET_NAME SHARED ${SOURCES}) target_include_directories(TARGET_NAME PUBLIC ${INCLUDE_DIRECTORIES} ) target_link_libraries(TARGET_NAME ${OpenCV_LIBS} ${catkin_LIBRARIES}) # fill this up with the dependencies you want for eg opencv add_executable(edge_detection_bin src/EdgeDetector.cpp ) target_include_directories(edge_detection_bin PUBLIC ${INCLUDE_DIRECTORIES} ) target_link_libraries(edge_detection_bin TARGET_NAME) add_executable(edge_srv_server_node src/edge_srv_server_node.cpp) target_link_libraries(edge_srv_server_node ${OpenCV_LIBS} ${catkin_LIBRARIES} edge_detection) add_dependencies(edge_srv_server_node edge_detection) add_executable(edge_srv_client_node src/edge_srv_client_node.cpp) target_link_libraries(edge_srv_client_node ${catkin_LIBRARIES} edge_detection) add_dependencies(edge_srv_client_node edge_detection) ## Declare a C++ library add_library(${PROJECT_NAME} src/EdgeDetector.cpp )
错误根源是你用file(GLOB_RECURSE CPP_FILES ${PROJECT_SOURCE_DIR}/src/*.cpp)把所有src下的cpp文件(包括带main函数的服务端、客户端节点文件)都打包进了TARGET_NAME共享库。库文件里不能包含main函数,因为每个可执行程序只能有一个main入口,而你把两个带main的文件都放进库,后续编译可执行文件时就会出现重复定义。
修复步骤:
- 移除通过
GLOB_RECURSE批量打包所有cpp到库的代码,改为仅将无main函数的类实现文件(比如EdgeDetector.cpp)加入库。 - 清理冗余的可执行文件定义(比如
edge_detection_bin是多余的,因为EdgeDetector是类不是可执行程序)。 - 确保服务端、客户端可执行文件仅链接必要的库,不重复打包代码。
修改后的关键Build部分代码:
########### ## Build ## ########### include_directories( include ${catkin_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} ) # 仅将类实现文件加入库,排除带main的节点文件 add_library(${PROJECT_NAME} src/EdgeDetector.cpp ) target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS} ${catkin_LIBRARIES}) # 编译服务端节点,仅用自身cpp文件,链接项目库 add_executable(edge_srv_server_node src/edge_srv_server_node.cpp) target_link_libraries(edge_srv_server_node ${PROJECT_NAME} ${OpenCV_LIBS} ${catkin_LIBRARIES}) add_dependencies(edge_srv_server_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) # 编译客户端节点,仅用自身cpp文件,链接项目库 add_executable(edge_srv_client_node src/edge_srv_client_node.cpp) target_link_libraries(edge_srv_client_node ${PROJECT_NAME} ${catkin_LIBRARIES}) add_dependencies(edge_srv_client_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
额外注意点:
- 不要用
GLOB_RECURSE批量添加源文件到库,显式列出需要的文件更可靠,避免意外包含入口文件。 - 可执行文件的依赖项建议使用
${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS},确保ROS消息/服务生成的目标被正确依赖。 - 移除冗余的
TARGET_NAME库和edge_detection_bin可执行文件定义,避免重复编译和链接错误。
内容的提问来源于stack exchange,提问作者Bilal

