Ask Your Question
0

using an external library: C versus C++ issue

asked 2016-02-19 16:20:52 -0500

I downloaded a vendor's library for accessing analog I/O ( http://www.rtd.com/software/CM/aAIO/a... ) on their motherboard ( http://www.rtd.com/PC104/CM/CMX32/CMX... ) and it works fine. I can compile the driver, install the driver, compile the library, compile the example usage code and run the example usage code that uses the library. It works like a charm. All the compiles use the command line "make" command. My problem is that I can't figure out how to get this exact same example code to compile in my catkin workspace and then add ROS code into it so I can publish the analog readings as ROS topics.

(Actually the link to the tarball above is old and the vendor emailed me a new version that is not on their website yet. Let me know if you would like me to get that corrected tarball to you.)

The example code I want to start with is "soft_trig.c" from the examples folder. I can copy that file into my catkin package, add it to the CMakeLists.txt, get it to compile as straight C code linked to the library without any ROS calls, and even execute it using rosrun just fine.

Here is my working CMakeLists.txt:

cmake_minimum_required(VERSION 2.8.3)
project(ros_aaio_node)

find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
)

catkin_package(
)

include_directories(
  ~/aaio/include
  ${catkin_INCLUDE_DIRS}
)

link_directories(~/aaio/lib)

add_executable(ros_aaio_node src/soft_trig.c)

target_link_libraries(ros_aaio_node
  rtd-aaio
  ${catkin_LIBRARIES}
)

So now I want to add ROS stuff to the file so I can publish data as ROS Topics. This is where I don't know what to do. I added

#include <ros/ros.h>

to the file and I got lots of compile errors. Lots of header files were not found.

It occurred to me that all my other ROS code was cpp files, not c files, so I renamed the file to soft_trig.cpp and changed the executable line in the CMakeLists.txt file too and I get a lot of different compile errors now. Tons of deprecated conversion warnings and several invalid conversion errors.

I saw some working code on another project where a coworker had been using a straight C compiled library with their ROS code and they used these two lines in their CMakeLists.txt:

set(CMAKE_C_FLAGS "-std=c99" )
set(CMAKE_CXX_FLAGS "-fpermissive")

So I tried that and all the compiler warnings and errors went away. But now I get a whole slew of undefined reference errors during linking.

Linking CXX executable ~/catkin_ws/devel/lib/ros_aaio_node/ros_aaio_node
CMakeFiles/ros_aaio_node.dir/src/soft_trig.cpp.o: In function `main':
soft_trig.cpp:(.text+0x851): undefined reference to `aAIO_Open(aAIO_Descriptor**, unsigned char)'
soft_trig.cpp:(.text+0x873): undefined reference to `aAIO_Return_Status(aAIO_Descriptor*, int, char*)'
soft_trig.cpp:(.text+0x8a0): undefined reference to `aAIO_Reset(aAIO_Descriptor*)'
soft_trig.cpp:(.text+0x8c2): undefined reference to `aAIO_Return_Status(aAIO_Descriptor*, int, char*)'
soft_trig.cpp:(.text+0x934): undefined reference to `aAIO_Install_ISR(aAIO_Descriptor*, void (*)(unsigned int), void (*)(unsigned int), void (*)(unsigned int), void (*)(unsigned int), void (*)(unsigned ...
(more)
edit retag flag offensive close merge delete

1 Answer

Sort by ยป oldest newest most voted
3

answered 2016-02-20 02:11:07 -0500

gvdhoorn gravatar image

There are (at least) two issues here (both of which are - strictly speaking - actually not very ROS specific):

  1. compiling C code with a C++ compiler
  2. C++ name mangling

re 1): as you discovered, renaming a file with C code doesn't necessarily make it (valid) C++, hence the need for the compiler flags. Warnings like deprecated conversion are exactly what one would expect.

re 2): linking probably fails because C++ mangles names. Linker is looking for ?Fi_i@@YAHH@Z, mfg library exports int Fi_i(int bar). Compiling C as C++ is most likely the cause.

Suggestion: treat the library you got from the mfg as just another system dependency.

Use the normal make, (sudo) make install procedure to install the mfg lib and headers into /usr/local (or wherever it installs), like you already did before you "add(ed) ROS stuff". Then either - as you do now - hard-code the location of the headers and library in your CMakeLists.txt (not recommended), or write a minimal FindAAIO.cmake (or whatever you name it) that searches for the library and headers at CMake configuration time (highly recommended).

Up to here everything is actually non ROS-specific: this is a normal CMake workflow.

For your ROS node(s), just #include <..> the necessary headers from the mfg library into your C++ sources, but make sure they already do something like:

#ifdef __cplusplus
extern "C" {
#endif

...

#ifdef __cplusplus
}
#endif

This basically tells a C++ compiler to not mangle the names for any symbols declared inside those guards. I'd be surprised if the mfg library's headers don't already do this, but do check. This avoids the linker errors you encountered earlier.

Ideally your ROS node(s) would now be just a 'thin wrapper' around some AAIO library functions.

edit flag offensive delete link more

Comments

Thanks! Adding the extern "C" wrapper to all the vendor's header files appears to have worked!

Kurt Leucht gravatar imageKurt Leucht ( 2016-02-22 15:36:54 -0500 )edit
1

Alternatively you could extern "C" your #include <> statements (so in your own sources). That way you don't have to change the vendor files.

gvdhoorn gravatar imagegvdhoorn ( 2016-02-23 01:21:01 -0500 )edit

That's even better! Thanks!

Kurt Leucht gravatar imageKurt Leucht ( 2016-02-23 08:34:01 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2016-02-19 16:20:52 -0500

Seen: 1,493 times

Last updated: Feb 20 '16