adamgreen / gcc4mbed

Project to allow GCC compilation of code using mbed SDK libraries.
172 stars 68 forks source link

Undefined reference when compiling rosserial #64

Closed naoki-mizuno closed 7 years ago

naoki-mizuno commented 7 years ago

I've been trying to use rosserial with gcc4mbed but have been getting the following undefined reference errors when compiling.

Linking LPC1768/rosserial-mbed.elf
LPC1768/main.o: In function `ros::NodeHandle_<MbedHardware, 25, 25, 512, 512>::setNow(ros::Time&)':
/home/naoki/ros/ubuntu/lib/ros_lib/ros/node_handle.h:329: undefined reference to `normalizeSecNSec'
collect2: error: ld returned 1 exit status
make: *** [LPC1768/rosserial-mbed.elf] Error 1

normalizeSecNSec is defined in ros/time.h and implemented in time.cpp, found in https://developer.mbed.org/users/garyservin/code/ros_lib_kinetic/.

The problem doesn't reproduce when I use the online compiler so I assumed it was something related to gcc4mbed. I spent some time looking into my Makefile, gcc4mbed.mk, and some other stuff but I had no idea where to start so I was wondering if you had some insight on this issue?

Environments

Environment 1

Environment 2

Environment 3

Steps to Reproduce

  1. hg clone https://developer.mbed.org/users/garyservin/code/ros_lib_kinetic/
  2. hg clone https://developer.mbed.org/users/sam_grove/code/BufferedSerial/
  3. hg clone https://mbed.org/users/sam_grove/code/Buffer/
  4. mv Buffer*/*.{h,cpp} ros_lib_kinetic
  5. Set USER_LIBS to /path/to/ros_lib_kinetic
  6. Prepare the following Makefile and main.cpp and run make

Files

Makefile

PROJECT := rosserial-mbed
DEVICES := LPC1768

include $(GCC4MBED_DIR)/build/gcc4mbed.mk

main.cpp

#include <mbed.h>
#include <ros.h>

int main() {
    ros::NodeHandle nh;
    return 0;
}
adamgreen commented 7 years ago

I can't even get the code to compile w/ the above repro steps.

These are just some of the many compile errors I get:

Compiling main.cpp
In file included from ../../gcc4mbed.delete/external/mbed-os/platform/Callback.h:19:0,
                 from ../../gcc4mbed.delete/external/mbed-os/rtos/Thread.h:27,
                 from ../../gcc4mbed.delete/external/mbed-os/rtos/rtos.h:28,
                 from ../../gcc4mbed.delete/external/mbed-os/mbed.h:39,
                 from main.cpp:1:
../ros_lib_kinetic/std_msgs/string.h: In member function 'virtual int std_msgs::String::serialize(unsigned char*) const':
../ros_lib_kinetic/std_msgs/string.h:26:47: error: 'strlen' was not declared in this scope
       uint32_t length_data = strlen(this->data);
                                               ^
../ros_lib_kinetic/std_msgs/string.h:29:57: error: 'memcpy' was not declared in this scope
       memcpy(outbuffer + offset, this->data, length_data);

How do you work around those to get as far as the linker error?

normalizeSecNSec is defined in ros/time.h and implemented in time.cpp, found in https://developer.mbed.org/users/garyservin/code/ros_lib_kinetic/.

When you look at your build output, do you see time.cpp getting built?

adamgreen commented 7 years ago

I moved from macOS to Ubuntu and got the code to compile and now I have reproduced you linker error. I will debug it later tonight and let you know what I find.

naoki-mizuno commented 7 years ago

@adamgreen Thanks for looking into this! Please let me know if there's anything I can do to help!

adamgreen commented 7 years ago

Rename ros_lib_kinetic/ros/time.h to ros_time.h and fix the couple of #includes that then fail.

Deep down in the newlib Standard C Library, there is a stat.h which #includes time.h and it picked up the ROS one instead of the Standard C Library version. The really freaky thing is that this caused the normalizeSecNSec() function to be declared as a C function in the global namespace instead of a C++ name mangled function in the ros:: namespace. That's why it failed to link.

naoki-mizuno commented 7 years ago

Fix confirmed!! Thanks a bunch for tackling this problem! I'll open up an issue in the rosserial repo to see what the guys think about renaming time.h.

adamgreen commented 7 years ago

It is a side effect of how the mbed build system places every folder for the library in the include path. If only the root of that ros_lib_kinetic project was in the include path and you always #include "ros/time.h" to get that header then it would work but I can't do that with the include path in gcc4mbed as it would break other mbed based projects.

My macOS compilation issue is similar since on macOS and Windows, String.h in the ROS project will typically be picked up if you #include <string.h> since they are case-insensitive.

PS: Happy to hear that it solved your problem though!

naoki-mizuno commented 7 years ago

Hmm... I see. Does that mean this is a problem that appears only on mbed and not on other platforms such as Arduino?

adamgreen commented 7 years ago

Does that mean this is a problem that appears only on mbed and not on other platforms such as Arduino?

I suspect so. This is probably a mbed/newlib/gcc only issue.

I don't think it is gcc4mbed specific though. I would have expected it to happen if you exported to GCC_ARM from the online compiler as well.

adamgreen commented 7 years ago

@naoki-mizuno I am re-opening this issue since I think there is a way that I can default it to the current include behavior but allow for a tweak in the settings which will allow the ROS code to build unmodified. I should have something for you to try in a day or so.

adamgreen commented 7 years ago

Updated steps which should allow you to use the ROS code as is without renaming it. These steps also allow it to build without error on my MacBook.

  1. Pull down the latest gcc4mbed master branch to get the change that I just made: git clone git@github.com:adamgreen/gcc4mbed.git
  2. hg clone https://developer.mbed.org/users/garyservin/code/ros_lib_kinetic/
  3. hg clone https://developer.mbed.org/users/sam_grove/code/BufferedSerial/
  4. hg clone https://mbed.org/users/sam_grove/code/Buffer/
  5. mkdir src
  6. cd src
  7. Prepare the following Makefile and main.cpp in the src/ folder and run make

Makefile

PROJECT      := rosserial-mbed
DEVICES      := LPC1768
GCC4MBED_DIR := ../gcc4mbed
USER_LIBS    := !../ros_lib_kinetic ../BufferedSerial ../Buffer

include $(GCC4MBED_DIR)/build/gcc4mbed.mk

main.cpp

#include <mbed.h>
#include <ros.h>

int main() {
    ros::NodeHandle nh;
    return 0;
}

I moved the setting of USER_LIBS into Makefile and had it build BufferedSerial and Buffer folders as libraries so that their sources don't need to be manually copied into ros_lib_kinetic/. The ! prefix on the !../ros_lib_kinetic foldername in USER_LIBS is what stops the recursive include path from being generated.

naoki-mizuno commented 7 years ago

Wow, you have no idea how happy I am right now! :laughing: I've confirmed that the new ! prefix works on Ubuntu and also a macOS El Capitan that I had access to. Thank you for the fix, and also for the awesome project!

adamgreen commented 7 years ago

Excellent!

I figured I should try to keep USER_LIBS working with ROS code as well as possible since that is where the request originated.

ghost commented 6 years ago

I actually tried the last fixed suggested, I ran into this one:

" make Preprocessing ../gcc4mbed/external/mbed-os/targets/TARGET_NXP/TARGET_LPC176X/device/TOOLCHAIN_GCC_ARM/LPC1768.ld make: ../gcc4mbed/gcc-arm-none-eabi/bin/arm-none-eabi-gcc: Command not found ../gcc4mbed/build/device-common.mk:201: recipe for target 'LPC1768/rosserial-mbed.ld' failed make: *** [LPC1768/rosserial-mbed.ld] Error 127 " Help is appreciated!

adamgreen commented 6 years ago

@MomoTavas That error would indicate that make can't find and/or execute the version of arm-none-eabi-gcc that should have been installed when you ran the gcc4mbed installation script.