0
votes

I have 3 CMake projects: myapp-avr (executable for AVR), myapp-unix (executable for Unix) and my_lib (a c++ static library imported by the executables). When I compile the MyLib project I have no problems at all. I can also successfully compile both myapp-avr and myapp-unix projects. However, I get errors when linking my app-avr such as "undefined reference to".

I uploaded an example to GitHub: https://github.com/cajomferro/basic-cmake. I have based my CMake structure on Pablo Ariasal sample project: https://github.com/pabloariasal/modern-cmake-sample.

I now know that the problem is related with the -isystem option. How can it be that the same exact command works with -I option but not with -isystem option (which is the one intended for imported/vendor libraries)?

Doesn't work: (auto-generated by CMake)

/usr/local/CrossPack-AVR/bin/avr-g++ -DARDUINO=10805 -DF_CPU=16000000L -isystem mylib/include -Os -g -w -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -flto -mmcu=atmega328p -std=gnu++11 -o src/main.cpp.obj -c src/main.cpp

Works:

/usr/local/CrossPack-AVR/bin/avr-g++ -DARDUINO=10805 -DF_CPU=16000000L -I mylib/include -Os -g -w -fpermissive -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -flto -mmcu=atmega328p -std=gnu++11 -o src/main.cpp.obj -c src/main.cpp


According to avr-g++ manual, -isystem means: Search dir for header files, after all directories specified by -I but before the standard system directories. Mark it as a system directory, so that it gets the same special treatment as is applied to the standard system directories

Moreover, when reading about the -I options, avr-g++ says: you should not use this option to add directories that contain vendor-supplied system header files (use -isystem for that)

I suppose this is the reason why CMake automatically generates a Make file with the -isystem option rather than using -I. Because in my CMake configuration I link libraries with the find_package() command, CMake interprets this as a vendor-supplied system?!

This project works just fine with clang (which also uses -isystem). My problem is with avr-g++.

Anyone had problems before with the -isystem using avr-g++? Is it possible to force CMake to use -I?? Thank you!!

1
I'm not really sure what your question is here. The -I and -isystem do different things. So... the things they do are different. Related. But different. Most 3rd party libraries ought to be done with -I, except for the few that feign to be the other kind (I'm looking at you, Boost).Eljay
Maybe you included the header once inside an extern "C" block and then you included it again outside of such a block. Without a minimal reproducible example, it is hard to tell what you are doing wrong. Make sure you do not include headers inside extern "C" blocks, and also put #pragma once at the top of your header to make sure it only gets included once.David Grayson
Thank you for your answers. I updated my question in order to better explain my problem.Carlos Mão de Ferro

1 Answers

1
votes

Problem solved! Apparently -isystem has a different behaviour on GNU compiler, according to https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html:

On very old systems, some of the pre-defined system header directories get even more special treatment. GNU C++ considers code in headers found in those directories to be surrounded by an extern "C" block.

These guys had a similar problem: https://github.com/conan-io/conan/issues/269.

So in order to avoid this mess, just inform CMake to use -I instead. A simple line is needed: NO_SYSTEM_FROM_IMPORTED ON (https://cmake.org/cmake/help/latest/prop_tgt/NO_SYSTEM_FROM_IMPORTED.html).

A example is:

set_target_properties(my_target
    PROPERTIES
    NO_SYSTEM_FROM_IMPORTED ON
    )

A full example is found in my CMakeLists.txt of myapp-avr executable: https://github.com/cajomferro/basic-cmake/blob/master/myapp-avr/CMakeLists.txt.