Arduino CMake build system

Arduino is a great development platform, which is easy to use. It has everything a beginner should need. The Arduino IDE simplifies a lot of things for the standard user, but if you are a professional programmer the IDE can feel simplistic and restrictive.

One major drawback of the Arduino IDE is that you cannot do anything without it, which for me is a complete buzz kill. Thats why I created an alternative build system for the Arduino using CMake.

CMake is great corss-platform build system that works on practically any operating system. With it you are not constrained to a single build system. CMake lets you generated the build system that fits your needs, using the tools you like. It can generate any type of build system, from simple Makefiles, to complete projects for Eclipse, Visual Studio, XCode, etc.

The Arduino CMake build system integrates tightly with the Arduino SDK. I'm currently basing on version 0022 of the Arduino SDK.

Can be found at: GitHub - queezythegreat/arduino-cmake: Arduino CMake Build system

Any feedback, comments, or ideas are welcomed. I'm trying to create a reliable alternative to the Arduino IDE.

QueezyTheGreat

queezy, this looks great. nicely done. i'll take the leap and try it out. a couple of quick comments after reading your documentation:

make wire_master_reader-serial

minor quibble, but that's a lot of typing. would be maybe nicer to just require "make serial"?

will using CMake allow me to spec my own include directory for libraries outside of the arduino IDE libraries directory? see my topic posted here: http://arduino.cc/forum/index.php/topic,59604.0.html

what if i want to make a larger build that builds all my libs first, and then compiles the firmware image that depends on those -- similar to how a standard Makefile might work.

so, for example:

project/
--- BlinkLibrary
--- BlinkLibrary.cpp
--- BlinkLibrary.h
--- Makefile
--- Blink
--- Blink.cpp
--- Makefile
--- Makefile

The root level makefile will build BlinkLibrary, then build Blink and include the output from BlinkLibrary -- is something like this possible?

Thanks,
Davis

zenocon:
queezy, this looks great. nicely done. i'll take the leap and try it out. a couple of quick comments after reading your documentation:

make wire_master_reader-serial

minor quibble, but that's a lot of typing. would be maybe nicer to just require "make serial"?

Actually there is a reason why I didn't add a serial target. The reason is that build system can support multiple firmware images, so you can have one build tree for multiple arduinos.

There is a upload target for mass uploading of firmware images, but for the serial terminal this isin't possible...

Also the reason why this target is so long is because the serial target has the forllowing format:

${TARGET_NAME}-serial

So everything depends on the target name.

zenocon:
will using CMake allow me to spec my own include directory for libraries outside of the arduino IDE libraries directory? see my topic posted here: http://arduino.cc/forum/index.php/topic,59604.0.html

Yes, currently the system look for two places for Arduino libraries. In the current directory of the target being defined, and in ${ARDUINO_SDK_PATH}/libraries. I can always add a user defined setting for adding custom search paths for Arduino libraries.

zenocon:
what if i want to make a larger build that builds all my libs first, and then compiles the firmware image that depends on those -- similar to how a standard Makefile might work.

so, for example:

project/
--- BlinkLibrary
--- BlinkLibrary.cpp
--- BlinkLibrary.h
--- Makefile
--- Blink
--- Blink.cpp
--- Makefile
--- Makefile

The root level makefile will build BlinkLibrary, then build Blink and include the output from BlinkLibrary -- is something like this possible?

Thanks,
Davis

CMake automatically resolves dependencies for you, so if you define a firmware image which depends on another library, CMake will first build that library. So you can have very complex dependencies....

The ${TARGET_NAME}_LIBS options is exactly for that, it works for firmware and library targets.

Hope that explains your questions,

QueezyTheGreat

Awesome -- yes, that answers most of my questions. I'm going to try it out very shortly and will get you some feedback. It looks just like what I'm looking for.

Yes, currently the system look for two places for Arduino libraries. In the current directory of the target being defined, and in ${ARDUINO_SDK_PATH}/libraries. I can always add a user defined setting for adding custom search paths for Arduino libraries.

One follow-up to this -- and this may just be my ignorance with Arduino builds in general, but when you include libraries are you expecting the compiled static libs (e.g. library.a), or just the sources? In the Arduino docs, they tell you to drop in a library in the ${ARDUINO_SDK_PATH}/libraries as a folder with the source code (.cpp/.h) and keywords.txt. I assume they compile it all to some temp dir, and link it together.

With your build system, what would a simple dir layout look like if I don't want to include anything from ${ARDUINO_SDK_PATH} and I have a simple firmware build that depends on a library build?

zenocon:
One follow-up to this -- and this may just be my ignorance with Arduino builds in general, but when you include libraries are you expecting the compiled static libs (e.g. library.a), or just the sources? In the Arduino docs, they tell you to drop in a library in the ${ARDUINO_SDK_PATH}/libraries as a folder with the source code (.cpp/.h) and keywords.txt. I assume they compile it all to some temp dir, and link it together.

With your build system, what would a simple dir layout look like if I don't want to include anything from ${ARDUINO_SDK_PATH} and I have a simple firmware build that depends on a library build?

All Arduino type libraries, meaning a directory which has the same name as the include (for example #include <LibraryName.h>) like so:

LibraryName/
`- LibraryName.h

is considered a Arduino library (all sources in that library directory get included in the build). Every library found gets automatically built in the build system, so no static libraries are required when it comes to Arduino type libraries (because the get automatically built).

If you specify a library in the dependencies that is not found part of the build system, it then looks for libraries in the standard system paths.

So if you create a directory that has the same name as the include statement and place it in the same directory as the CMakeLists.txt it will get built automatically as a Arduino type library (no user intervention required).

Does that answer your question?

Also I have updated the documentation to include the answers I gave you in the previous post...

QueezyTheGreat

Hi, wanted to give a status update.

As of Sunday, all platforms are now supported out of the box in Arduino CMake. You can build on Linux, Windows and Mac OS X.
Instruction for setting up the environment are on the main project page on GitHub (GitHub - queezythegreat/arduino-cmake: Arduino CMake Build system).

The only thing that is left to be done is to create Sketch conversion, so that I works exactly like the Arduino IDE.

If somebody is interested in instruction for getting a Eclipse environment up and running please let me know, I'll add it to the documentation.

Bye for now,

QueezyTheGreat

Queezy,

I, too, prefer an alternative to the Arduino IDE. Don't get me wrong, it's a great tool and awesome for it's intended goal. But it lacks the sophistication of the rest of the tools in my "toolbox". Of which CMake is one. (For this conversation, Emacs and gcc are the other ones.)

Did a quick git clone to take a look at your project. I have been working on a FindArduino.cmake myself; however, your's has quite a bit more sophistication! Great job!

Lets get some caveats out of the way: while I do use and like CMake, I am NOT a guru, but I'm not a complete neophyte, either. :slight_smile:

Here's a suggestion: for your processing style changes, do something like Qt does. For example:
find_package(Arduino)
file( GLOB pde_ *.pde) # find all the pde files
arduino_wrap_source(cpp_ ${pde_}) # convert the pde files into cpp files and store their names in the cpp_ variable

Now for a criticism: too complicated, and too much deviation from "normal" CMakeLists.txt files.

It should be enough to do something like this:
set(ARDUINO_PLATFORM uno)
find_package(Arduino REQUIRED SPI RTC)

include_directories(${ARDUINO_INCLUDE_DIR})
file(GLOB cpp_ src/*.cpp)
add_executable(${target_name} ${cpp_})
target_link_libraries(${target_name} ${ARDUINO_LIBS} )
arduino_flash${target_name})

To generate a target that can be flashed to the device via "make flash". I think this is more in the spirit of CMake?

Regardless, great job! I will look more at your files as time allows. Are you interested in help?

SB

The style of my CMake system is for complicated setups, and is based on what I use at work where we have very large and complex projects (using C, C++, Python, ASM, QT, IDL, etc). So yes this is a little bit more complicated but giving you much more flexibility.

I rather have a configuration where I describe the target (declarative programming Declarative programming - Wikipedia) rather than how to generate the target.

Things like:

ScottyB:
include_directories(${ARDUINO_INCLUDE_DIR})
file(GLOB cpp_ src/*.cpp)
add_executable(${target_name} ${cpp_})
target_link_libraries(${target_name} ${ARDUINO_LIBS} )
arduino_flash${target_name})

are boilerplate code, which gets repeated over and over in large projects. So my build sytem style eliminates all of which is redundant. When you have 50 targets in you build system you will understand how much redundancy that is (especially when working with QT) :slight_smile:

Another reason for using this style is extending it to support more options (and being backwards compatible) is much easier using this style.

I do agree with you that this is a little bit non standard when it comes to CMake, but this style has been used with great success on big projects for over 2 years.

Anyway any help is always appreciated,

QueezyTheGreat

queezythegreat:
are boilerplate code, which gets repeated over and over in large projects. So my build sytem style eliminates all of which is redundant. When you have 50 targets in you build system you will understand how much redundancy that is (especially when working with QT) :slight_smile:

The beauty of the boilerplate code is its boilerplate-ness! Any macro/function I or someone else already have works with little change. I'm not suggesting your approach is wrong for you or your projects; rather, make the expected work and then provide whatever macros/functions you are accustomed to. (Of course, those should already exist in your cmake modules path so that they need not be rewritten...)

Remember, I said I'm not a CMake guru. 50 targets does not impress me. :wink: And Qt is an absolute dream from CMake regardless of project complexity. I kinda think it's because it follows the same rules everything else does.

And you haven't done away with redundant code, you've only changed the way it looks. From this:

set(ARDUINO_PLATFORM uno)
find_package(Arduino)
include_directories(${ARDUINO_INCLUDE_DIR})
add_executable(proj file.cpp)
target_link_libraries(proj ${ARDUINO_LIBS})
generate_arduino_flash(proj PORT /dev/USB0)

To this:

find_package(Arduino)
set(proj_BOARD mega2560)
set(proj_SRCS wire_master_reader.cpp)
set(proj_PORT /dev/ttyUSB0)
generate_arduino_firmware(proj)

5 lines or 6 lines? (And only because I think it's wrong to put the include_directories into the FindArduino.cmake file.) Furthermore, you've made it hard for me to add the EXCLUDE_FROM_ALL property to my target! (This will be worse if CMake adds more properties like EXCLUDE_FROM_ALL in the future...

Another reason for using this style is extending it to support more options (and being backwards compatible) is much easier using this style.

I am not convinced. I think this is easily done by the user in their own project specific macro/function. But I'm willing to be wrong... Convince me.

I do agree with you that this is a little bit non standard when it comes to CMake, but this style has been used with great success on big projects for over 2 years.

Essentially I'm arguing familiar is good! If everything looks and acts the same, then for the most part I can update my CMake files without going to documentation. I can use my common.cmake file with expected results.

For example, Boost and Qt generally look the same from a CMake perspective. It's easy to combine them. If either of them went a non-standard route, I might have a problem using them together on a project.

Another example: Lets say I wanted to create 10 executables that all use my loc library. I can, with the boilerplate approach, compile my loc library once, and link 10 times. Show me how to do this your way. (Really, it's such a non-issue for Arduino because of the limited resources of the system. But it is an issue for the bigger picture.)

Again, your way isn't wrong, I just want the familiar. Because it will work with my current cmake module files!

It's a matter of preference. I've written the modules the way I always written them, and it's the style I use in my build systems at work. I really don't feel like rewriting.

If you have suggestions how to modify what I have done so that it works for both styles, I'm open to suggestion.

QueezyTheGreat

queezythegreat:
It's a matter of preference. I've written the modules the way I always written them, and it's the style I use in my build systems at work.

I respect that.

If you have suggestions how to modify what I have done so that it works for both styles, I'm open to suggestion.

Suggestions? You ask for so little!

I get time in fits and spurts. This weekend I spent a little time working on my FindArduino.cmake implementation before stumbling on yours. I'm happy to keep right on coding mine. It's almost does everything I need it to do.

But if your open to incorporating patches, we could work together. At the moment, I don't have a lot of drive to add the extra stuff (e.g. sketch to cpp is interesting, but as a c++ guy it's off my radar), but I might if I weren't the only developer.

I'd merge as time allows. Of course, today I wasted time typing these entries instead of code. :frowning:

SB

I would be happy to integrate your patches if you have any! The sketch conversion is tricky business, without a proper lexer/parser it's unpractical to do a good job. I started on replicating what the Arduino IDE does in CMake but I think it's not worth the effort (you can find my initial implementation on GitHub in cmake/modules/ArduinoPreprocessing.cmake).

I personally don't even own an Arduino :slight_smile: My build system was created after I spent 2 hours helping a friend with his arduino and I got so frustrated with the IDE (it actually drove me crazy). I then decided to roll my own alternate build system using CMake. So the build system was created so that could build from the command line while I was creating a small library for my friend (he isn't any good at C/C++).

So if you want to have you're changes integrated, please fork my project and send me pull request when you have something.

Hope to hear from you,

QueezyTheGreat

Regarding the IDE, it is a great tool to get started with, but it doesn't work very well with external editors.

If merging of the sources is easy, I'll provide the updates.

What are the possible values for _BOARD? I have a Sanguine AT1284P, and am not sure the correct way to specify it.

Digging into this more, I see where the boards.txt file is set into the cmake variable, by looking in the hardware folder. On my setup, which works with the IDE, my hardware folder has two subdirectories: arduino and sanguino. Any ideas on what needs to be done to integrate the two in the cmake setup?

I seem to get past the error I was receiving (the board was not found) by consolidating the two directory structures, I'm just not sure that is the correct thing to do. Any advice appreciated.