queezythegreat / arduino-cmake

Arduino CMake Build system
645 stars 216 forks source link

Missing library while Including another library file without including it's main file #105

Closed kiler129 closed 9 years ago

kiler129 commented 9 years ago

Hello! I 've found bug in CMake scripts, which cost me around 24h of ripping hairs from my head :) Some libraries besides main file (named after library name and it's folder) contains another helper files. Everything works as expected if project file includes main library file - arduino-cmake scripts scans whole library, finds all of it's files, all of them are linked correctly. There's only scenario, which I assume @queezythegreat, didn't expected - including library side file WITHOUT including main library file first.

Let's me use an real example - MPU6050 library (https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/MPU6050). Besides core "MPU6050.h" file it's supplied with two helper files: "MPU6050_6Axis_MotionApps20.h" and "MPU6050_9Axis_MotionApps41.h". Examples states, that library should be used by including these two files, and not "MPU6050.h". I slightly modified "Arduino.cmake" to print debug informations while searching libraries:

            foreach(SRC_LINE ${SRC_CONTENTS})
                if("${SRC_LINE}" MATCHES "^[ \t]*#[ \t]*include[ \t]*[<\"]([^>\"]*)[>\"]")

                    message(AUTHOR_WARNING "LINE: ${SRC_LINE} -> ${CMAKE_MATCH_1}")

                    get_filename_component(INCLUDE_NAME ${CMAKE_MATCH_1} NAME_WE)

                    get_property(LIBRARY_SEARCH_PATH
                                 DIRECTORY     # Property Scope
                                 PROPERTY LINK_DIRECTORIES)
                    foreach(LIB_SEARCH_PATH ${LIBRARY_SEARCH_PATH} ${ARDUINO_LIBRARIES_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libraries ${ARDUINO_EXTRA_LIBRARIES_PATH})
                        message(AUTHOR_WARNING "${LIB_SEARCH_PATH}/${INCLUDE_NAME}/${CMAKE_MATCH_1}")
                        if(EXISTS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}/${CMAKE_MATCH_1})
                            list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH}/${INCLUDE_NAME})
                            break()
                        endif()
                        if(EXISTS ${LIB_SEARCH_PATH}/${CMAKE_MATCH_1})
                            list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH})
                            break()
                        endif()
                    endforeach()
                endif()
            endforeach()

I've got expected output: screenshot 2015-01-03 01 58 58

Is there any workaround other than disabling autolibs? Unfortunately I don't know CMake language, so I'm unable to propose any path.

mdaffin commented 9 years ago

Note that I believe this is the way the official ide also works.

The IDE and cmake libs both look at the includes to see which libraries to add to the include path. This is a requirement of all Arduino libraries and is why you must include a .h file named after the directory the library is in.

In a way this is not a bug but how Arduino works, on the other hand I have hit this problem before and it is annoying to debug.

If you want your sketch to remain compatible with the ide just add the right include, the compiler will optimise it out anyway if you don't use it.

Personally I think we should keep the upstream behaviour to make it easier to switch from Arduino ide and cmake based projects, at least for projects that don't disable the autolibs.

On Sat, 3 Jan 2015 01:02 kiler129 notifications@github.com wrote:

Hello! I 've found bug in CMake scripts, which cost me around 24h of ripping hairs from my head :) Some libraries besides main file (named after library name and it's folder) contains another helper files. Everything works as expected if project file includes main library file - arduino-cmake scripts scans whole library, finds all of it's files, all of them are linked correctly. There's only scenario, which I assume @queezythegreat https://github.com/queezythegreat, didn't expected - including library side file WITHOUT including main library file first.

Let's me use an real example - MPU6050 library ( https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/MPU6050). Besides core "MPU6050.h" file it's supplied with two helper files: "MPU6050_6Axis_MotionApps20.h" and "MPU6050_9Axis_MotionApps41.h". Examples states, that library should be used using these two files, and rarely "MPU6050.h". I slightly modified "Arduino.cmake" to print debug informations while searching libraries:

        foreach(SRC_LINE ${SRC_CONTENTS})
            if("${SRC_LINE}" MATCHES "^[ \t]*#[ \t]*include[ \t]*[<\"]([^>\"]*)[>\"]")

                message(AUTHOR_WARNING "LINE: ${SRC_LINE} -> ${CMAKE_MATCH_1}")

                get_filename_component(INCLUDE_NAME ${CMAKE_MATCH_1} NAME_WE)

                get_property(LIBRARY_SEARCH_PATH
                             DIRECTORY     # Property Scope
                             PROPERTY LINK_DIRECTORIES)
                foreach(LIB_SEARCH_PATH ${LIBRARY_SEARCH_PATH} ${ARDUINO_LIBRARIES_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/libraries ${ARDUINO_EXTRA_LIBRARIES_PATH})
                    message(AUTHOR_WARNING "${LIB_SEARCH_PATH}/${INCLUDE_NAME}/${CMAKE_MATCH_1}")
                    if(EXISTS ${LIB_SEARCH_PATH}/${INCLUDE_NAME}/${CMAKE_MATCH_1})
                        list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH}/${INCLUDE_NAME})
                        break()
                    endif()
                    if(EXISTS ${LIB_SEARCH_PATH}/${CMAKE_MATCH_1})
                        list(APPEND ARDUINO_LIBS ${LIB_SEARCH_PATH})
                        break()
                    endif()
                endforeach()
            endif()
        endforeach()

I've got expected output: [image: screenshot 2015-01-03 01 58 58] https://cloud.githubusercontent.com/assets/1227834/5601063/40cbb9b6-92ec-11e4-9332-eb70c4881892.png

Is there any workaround other than disabling autolibs? Unfortunately I don't know CMake language, so I'm unable to propose any path.

— Reply to this email directly or view it on GitHub https://github.com/queezythegreat/arduino-cmake/issues/105.

kiler129 commented 9 years ago

@james147 Not quite. Arduino official IDE handles libraries differently than arduino-cmake. For example if I include "MPU6050_6Axis_MotionApps20.h" it require me to include both "Wire.h" and "I2Cdev.h" (regardless they are included in "MPU6050_6Axis_MotionApps20.h" already) - arduino-cmake handles these includes without any problems. Take a look at this example:

#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"

void setup() {
}

void loop() {
}

It compiles without any problems in official IDE but not using cmake - it raises error about missing "MPU6050_6Axis_MotionApps20.h". It's not a problem for me to include "MPU6050.h" before including "MPU6050_6Axis_MotionApps20.h" but it's just will not compile.

queezythegreat commented 9 years ago

Hi, I think this is a edge case that should not be supported. They should have made those helper files as separate libraries which depend on the core library.

It's not worth the development and maintenance costs to support this edge case. Although the the Arduino IDE supports this, I think this should not be possible.

kiler129 commented 9 years ago

@queezythegreat, could you propose any workaround at least? I've tried to include "LIBS MPU6050" but it has no effect.

kigster commented 9 years ago

You could fork the library, and inline the contents of the helper header files into the main header file.

ibalashov commented 8 years ago

The compilation workaround is

#include "MPU6050_6Axis_MotionApps20.h"
#include "MPU6050.h"