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.