본문 바로가기

ROS

[ROS] multiple definition of ... 오류

문제상황

  • 변수나 함수, 쓰레드 등을 헤더에 선언하였을 때, 다음과 같은 오류 메세지를 출력함.

error msg: multiple definition of ...

해결 방법 

(1) [추천] 헤더 파일에서 본인이 헤더에 선언한 변수와 함수를 Struct 또는 Class 내에 선언(묵시적 inline화)

(2) CMakeLists.txt 수정

(3) Inline 함수로 선언 

 

시간 없으신 분들은 여기까지 읽으시면 됩니다.

감사합니다. 

시간이 많은 분들을 위한 구구절절 설명

 

728x90

문제상황의 원인

  • 특정 헤더파일(.hpp 또는 .h) 가 서로 다른 소스 (.cpp 또는 .c)에서 여러번 include 되었을 때 나타나는 에러이다.
    • 즉, ROS 에서 각 노드 별로 동일 헤더에 대해서 중복으로 include 및 선언을 하다 보니, 컴파일러는 명확하게 인지하지 못하게 됨 
    • 여러 번 include 되면서 multiple definition을 정의
  • 함수나 변수를 헤더파일에 선언하는 것은 "header가 include 되는 각각의 translation(by compiler) 마다 각각의 definition이 정의되는 것"과 같음
  • 하나의 ROS 패키지에서는 한번의 definition만이 허용된다 : 정의는 반드시 한번만 이뤄져야 한다. (One Definition Rule)

해결법 (3가지)

(1)  선언된 변수 및 함수의 묵시적 inline 화 : Struct 또는 Class 내에 선언 

(2) CMakeLists.txt 수정

(3) inline 함수로 선언하여 해결한다.

 

(1) 선언된 변수 및 함수의 묵시적 inline 화

: 오류가 발생하는 변수나 함수를 struct 또는 class 내에 선언한다.

  • 오류가 발생한 변수 또는 함수의 선언을 struct와 class 내부로 옮긴다.
  • struct, class 내에 선언되는 함수는 자동적으로 inline화 된다.
  • inline화 되면 그 자체가 내용이 되므로, 호출을 통해 생기는 multiple definition 에러를 잡아줄 수 있다.
  • Declaring the variables and functions in the ‘struct’ or ‘class’ makes them appear in only one translation unit.

(2) 선언된 변수 및 함수의 묵시적 inline 화

: 문제가 생긴 header 파일을 하나의 library로써 CMake 파일에 명시한다.

  • 여러번 include 되는 헤더를 하나의 library로 CMakeLists.txt에 명시하여 multi-define 되지 않도록한다.
  • 단, 상호 간 dependency 를 주의해야한다. circle이 되지 않도록 항상 상위관계를 명확하게 선언해야한다

----

<구체적인 예시: 생략 가능>

Leishen 사의 lslidar c16 코드를 예시로 들어보자.

해당 소스의 주요 패키지는 크게 decoder, driver로 나누어 생각해볼 수 있다.

이중 decoder 패키지의 소스는

  • lslidar_c16_decoder.cpp
  • lslidar_c16_decoder_node.cpp
  • lslidar_c16_decoder_nodelet.cpp

으로 나눌 수 있다.

해당 패키지의 헤더 중 `lslidar_c16_decoder.h` src/lslidar_c16_decoder_node.cpp src/lslidar_c16_decoder.cpp 모두의 선언부에 #include <lslidar_c16_decoder/lslidar_c16_decoder.h>로 include 되는 것을 확인할 수 있다.

그러나, `lslidar_c16_decoder.h`내의 namespace lslidar_c16_decoder에서 class 또는 struct 밖에서 변수와 함수를 선언해도 문제가 되지 않는다.

해당 이유는 lslidar_c16_decoder 패키지의 CMakeLists.txt에서 확인할 수 있다.

 

...중략...
# Lslidar C16 Decoder
add_library(lslidar_c16_decoder
src/lslidar_c16_decoder.cpp
)
target_link_libraries(lslidar_c16_decoder
${catkin_LIBRARIES}
)
add_dependencies(lslidar_c16_decoder
${${PROJECT_NAME}_EXPORTED_TARGETS}
${catkin_EXPORTED_TARGETS}
)
# Lslidar C16 Decoder node
add_executable(lslidar_c16_decoder_node
src/lslidar_c16_decoder_node.cpp
)
target_link_libraries(lslidar_c16_decoder_node
lslidar_c16_decoder                           
${catkin_LIBRARIES}
)
add_dependencies(lslidar_c16_decoder_node
${${PROJECT_NAME}_EXPORTED_TARGETS}
${catkin_EXPORTED_TARGETS}
)
# Lslidar C16 Decoder nodelet
add_library(lslidar_c16_decoder_nodelet
src/lslidar_c16_decoder_nodelet.cpp
)
target_link_libraries(lslidar_c16_decoder_nodelet
lslidar_c16_decoder
${catkin_LIBRARIES}
)
add_dependencies(lslidar_c16_decoder_nodelet
${${PROJECT_NAME}_EXPORTED_TARGETS}
${catkin_EXPORTED_TARGETS}
)
... 중략 ...

위의 ./lslidar_c16_decoder/CMakeLits.txt 는 각각의 cpp 파일에 대한 라이브러리와 dependency를 각각 명시하고 있다.

add_library는 아래와 같으므로 

add_library (<사용자가_지정한_library_이름>
             소스1_경로/소스1.cpp
             소스2_경로/소스2.cpp
                ..중략..
)

 아래와 같이 'lslidar_c16_decoder' 라는 라이브러리명을 지정하고 해당 라이브러리는src/lslidar_c16_decoder.cpp 내에 선언된 정의를 지칭하는 것이다.

# Lslidar C16 Decoder
add_library(lslidar_c16_decoder
src/lslidar_c16_decoder.cpp
)

그러므로,

# Lslidar C16 Decoder node
add_executable(lslidar_c16_decoder_node
src/lslidar_c16_decoder_node.cpp
)
target_link_libraries(lslidar_c16_decoder_node
lslidar_c16_decoder
${catkin_LIBRARIES}
)
add_dependencies(lslidar_c16_decoder_node
${${PROJECT_NAME}_EXPORTED_TARGETS}
${catkin_EXPORTED_TARGETS}
)
# Lslidar C16 Decoder nodelet
add_library(lslidar_c16_decoder_nodelet
src/lslidar_c16_decoder_nodelet.cpp
)
target_link_libraries(lslidar_c16_decoder_nodelet
lslidar_c16_decoder
${catkin_LIBRARIES}
)

해당 부분은 decoder_node와 decoder_nodelet이 모두 src/ lslidar_ c16_ decoder.cpp 를 `target_link_libraries`를 통해 내부 라이브러리를 동일하게 링크하는 것으로 명시하여 각각의 .cpp 파일에서

#include <lslidar_c16_decoder/lslidar_c16_decoder.h>

를 중복으로 include하여도 multiple definition 오류가 나지 않는 것이다.

----

 

 

참고 링크: https://github.com/tongsky723/lslidar_C16, https://stackoverflow.com/questions/9959563/why-do-i-get-a-multiple-definition-error-while-linking, [ROS] multiple definition of ... 오류 | by Gyuwon Choi | Medium

https://github.com/tongsky723/lslidar_C16

728x90

'ROS' 카테고리의 다른 글

[ROS] rosbag 을 csv 로 변환  (0) 2022.08.16
[ROS] rosbag 을 csv 로 변환  (0) 2022.06.13