SmingHub / Sming

Sming - powerful open source framework simplifying the creation of embedded C++ applications.
https://sming.readthedocs.io
GNU Lesser General Public License v3.0
1.46k stars 349 forks source link

CMake build system for Sming #1684

Open frankdownunder opened 5 years ago

frankdownunder commented 5 years ago

Espressif have started using cmake for their ESP32 IDF development framework. Eventually, the existing system using make will be deprecated. cmake and ninja have many advantages, so I will take a look at cmake for Sming. Initially it will be an alternative way to build; further down the track it will help us target the ESP32 hardware also.

frankdownunder commented 5 years ago

Hi Mike, Slaff,

I pushed some changes to my fork at https://github.com/frankdownunder/Sming on branch “feature/cmake”

Install cmake and Ninja

Please take a look at /opt/Sming/Sming/CmakeLists.txt and the readme file at /opt/Sming/Sming/cmake/Readme.md for how to build

This new cmake approach is lacking in many respects, anyway I needed to start somewhere. In particular Ive used absolute paths which obviously must be changed., and the ar command at the end complains “/usr/bin/ar: u' modifier ignored sinceD' is the default (see `U')”

I also have used the same names for the options – eg ENABLE_CMD_EXECUTOR, which causes a multiple define error when using the old makefile

I had a lot trouble with -DPROGMEM_L32="attribute((aligned(4))) attribute((section(\".irom.text\")))" ) cmake really disliked the embedded space, and the quotes. I did get it working in the end however

I also found a bug in the compiler I think. The problem is that the compiler, when given the MMD option to generate dependencies, does not also do a compile. Instead it produces an output file of zero length. A workaround might be to have a python program that calls the compiler twice - first with MMD and the second time without. Until we have a workaround, Ninja is out of the question, pity.

FYI My version of xtensa-lx106-elf-g++ from /opt/esp-open-sdk/xtensa-lx106-elf/bin/ is 4.8.5 and the version within the Arduino folder is 4.8.2

mikee47 commented 5 years ago

I had a lot trouble with -DPROGMEM_L32="attribute((aligned(4))) attribute((section(".irom.text")))" ) cmake really disliked the embedded space, and the quotes. I did get it working in the end however

With PR #1704 this is now out of the makefiles and into fakePgmSpace.h, just need to detect mforce-l32 support and define MFORCE32 if detected.

P.S. Excellent start!

frankdownunder commented 5 years ago

Ninja seems to work now - a recent change to the compiler options was probably responsible for fixing it. So, to generate using ninja, cd build cmake .. -GNinja

frankdownunder commented 5 years ago

Re PROGMEM, I will add this: execute_process(COMMAND ${CMAKE_CXX_COMPILER} "--help=target" OUTPUT_VARIABLE OUT) if(${OUT} MATCHES "mforce-l32") set(MFORCE32 1) else() set(MFORCE32 0) ENDIF() But this doesnt look to be enough - can you confirm?

mikee47 commented 5 years ago

I think you also need to add -DMFORCE32=${MFORCE32} to target_compile_definitions.

aemseemann commented 5 years ago

Hi there,

glad to see that I am not the only one with an interest in a cmake-based build system for Sming.

I've done something very similar last year in the aftermath of another project and only recently came back to it with the intent of cleaning it up and eventually preparing it for upstream. You can check out my approach at https://github.com/aemseemann/Sming, branch 'cmake'. In its current state, it can generate rboot images and stand-alone images (now deprecated, as I've learned), which have been successfully tested on an ESP-01S board using a Linux build machine. However, it is based on the rather outdated sming-3.6 release and would need some work to adapt it to the recent repository reorganization.

Anyway, I would be happy to help with your efforts in adding CMake support to Sming!

Here are some thoughts/remarks (sorry for the lengthy text though...):

  1. Toolchain file: On your branch, compiler paths are hardcoded (minus an environment variable) in the CMakeLists.txt. As your comments in that file already point out, this is not an ideal solution. Instead, CMake's approach for cross compiling involves a so-called toolchain file (see my Sming/toolchain.cmake) that is given to the initial configure run via "-DCMAKE_TOOLCHAIN_FILE=...". This way, CMake 'knows' about the toolchain from the very beginning and is able to apply all the quirks and workarounds it would normally do for a GNU-based toolchain. In an ideal world, a suitable toolchain file would come with the toolchain (and maybe we can convince pfalcon to include one in esp-open-sdk in the future), but for the moment, I proposed to distribute it with Sming itself.
  2. Build system architecture: The Makefile-based build system essentially splits up the build process into the 'sming' part (Sming/Makefile) and the 'application+linking' part (Sming/Makefile-app.mk). While I in general agree to keeping these steps separated, the downside is replicating (and keeping in sync!) some of sming's build logic (e. g. config options, compiler flags, dependencies) in both files. From what I've seen on your branch, you followed the same approach with Sming/CMakeLists.txt for the sming part and samples/BasicBlink/CMakeLists.txt for the application part. While most of the duplication can be avoided by exploiting that CMake propagates compile flags and dependencies transitively, I would still object against putting sming-related build system logic into sming/BasicBlink/CMakeLists.txt (or a generic "CMakeLists-app.txt" version thereof), i. e. into a file that users copy out of the Sming repository to their own project. This is why I put all the build logic from Makefile-app.mk into Sming/sming.cmake, which is supposed to be included by the main CMakeLists.txt of the sample or user project (see samples/BasicBlink/CMakeLists.txt for an example).
  3. Configuration options: CMake already offers us a nice way to manage project specific configuration options via cached variables. Therefore, all sming-related config options should be exposed via option(...) or set(... CACHE ...) commands. This way, options can be easily inspected and modified on a per-project basis using tools like cmake-gui, without touching any CMake source file in the Sming repository. Also, CMake would take care of recompiling affected parts of the project after a config option has been changed.
  4. CMake build types: CMake natively supports Release, Debug, MinRelSize and RelWithDebInfo builds. Sming has SMING_RELEASE, ENABLE_GDB or neither. To meet user expectations, we should map them somehow, e. g.
    • Release/MinRelSize => set SMING_RELEASE and disable GDB by default
    • Debug => Do not set SMING_RELEASE and enable GDB by default
    • RelWithDebInfo => set SMING_RELEASE and enable GDB by default
      I mean, I would still keep SMING_RELEASE and ENABLE_GDB config options, but with different default values depending on CMAKE_BUILD_TYPE.
  5. Optimization/debug flags: This is closely related to the previous item. Sming currently uses a mixture of -Os, -Og, -g, -ggdb. CMake, otoh, has the following defaults per build type:
    • Release: -O3 -DNDEBUG
    • RelWithDebInfo: -O2 -g -DNDEBUG
    • Debug: -g
    • MinRelSize: -Os -DNDEBUG
      While -DNDEBUG probably does no harm, only MinRelSize agrees with Sming's current optimization options. Should we overwrite the defaults in the toolchain file (as I currently did, but which is not the recommended way) or should we declare MinRelSize the preferred build type? As a side note: I tried to build with -O2 once and received an obscure "undefined reference to stpcpy", which I could not find anywhere in Smings source code. Apparently, the optimizer found a pattern it could replace with this function, but unfortunately, it was stripped from libmicroc.a (or was never there in the first place).
  6. Compiler warning flags: Currently, the same compiler warning options are passed to Sming components and the user application. This might not be appropriate. While Sming code should adhere to a strict warning policy, we should not impose this restriction on the user application code. Also, the -Wno-... exclusions should be selected more fine-grained, i. e. a warning should not be disabled for the whole Sming project just because some random Arduino lib triggers it. Also, I am strongly in favor of -Werror for Sming code with no option to disable it.
  7. Arduino Libraries: While the current Makefiles thankfully made ARDUINO_LIBRARIES presetable and added EXCLUDE_LIBRARIES to restrict the amount of Arduino libraries, CMake offers a more natural way: Do not include any of them in libsming itself. Instead, create a separate library target for every Arduino lib that is only build when needed (add_library(... EXCLUDE_FROM_ALL ...)). To use any of them, user code has to link to them explicitly via target_link_libraries(...).
frankdownunder commented 5 years ago

I am overjoyed to see your contribution. While I have used cmake for a long time at work, I was just a user - someone else looked after the itty gritty, so I am just still learning how it fits together. It was the ESP32 cmake IDF environment that really got me hooked. It is very nice. I soon had an ESp32 project with Arduino as one component and my libraries and code all cooperating with cmake lists in each, all too easy. That was where I wanted to be, what I have so far was just to start the conversation. I has a look at yours and you have put a lot of work into it.

  1. Toolchain file: Totally agree.
  2. Build system architecture: Mike is about to commit some changes to target different architectures, eg ESP32 ESP8266 and Host. When the dust settles, this is going to be very significant - it will allow debugging on my PC without using Serial.print (I cant wait) and no more waiting for a flash to happen.So yes there may need to be some thought about which libraries get built and how to do so in a consistent fashion.
  3. Configuration options: all sming-related config options should be exposed via option(...) Agreed. I saw your comment about cmake-gui vs Kconfig, not sure about the pros and cons, they both look similar. My preference at this point would be KConfig since thats what is used for ESP32
  4. CMake build types: To meet user expectations, we should map them somehow, e. g. Release/MinRelSize => set SMING_RELEASE and disable GDB by default Debug => Do not set SMING_RELEASE and enable GDB by default RelWithDebInfo => set SMING_RELEASE and enable GDB by default Agreed
  5. Compiler warning flags: I favour turning on as many warnings as we can and making them al errors.
  6. Arduino Libraries: Keeping it simple for the end user - what is the down side in having all those libraries available in one library? It doesnt slow things down much that I can see.

So I am waiting till Mike has finished the Host stuff, before doing any more. In the mean time I want to revisit the ESP32 way of doing things to see if there is more to learn. The register_component() function seems to do a lot behind the scenes. . .

mikee47 commented 5 years ago

This is all looking very promising indeed! @aemseemann you mention the problem of replicating (and keeping in sync!) some of sming's build logic (e. g. config options, compiler flags, dependencies) in both files and I agree absolutely this needs fixing. I'll just point out now that I am not a CMake veteran, but integrating LWIP into the Host arch has been an interesting exercise in getting to grips with its abilities. So far so good!

So far, work on the makefiles has eliminated some duplication and making the build flow a little clearer, but what I didn't do was change the essential build logic. The next step would be to split the build up so each Component gets its own makefile (probably include rather than sub-make), containing logic for both Sming and App builds. @frankdownunder Yes, that's essentially what the logic behind register_component does, so I'd introduce something similar (although less elaborate) for this step.

That would eliminate the app/sming duplication problem. I stopped short of this step because I didn't want to clutter the tree with makefiles which could potentially conflict with CMake work. However, it would help to break the problem up into smaller, more manageable chunks, improve modularity and give us a way to keep the two build systems in sync, until such time as we decide to retire makefiles in favour of CMake.

A couple of variables I added to the makefiles are:

These should provide useful hints for migrating to CMake.

mikee47 commented 5 years ago

I've started looking at moving stuff out of the main makefiles into related components. This is what I have in mind:

  1. Each Component has a component.mk file which defines settings, submodules, etc. It will also specify any custom targets (additional makefiles) required.
  2. Each Component is built as a separate library, using a separate make instance (sub-make)
  3. Rename Makefile to sming.mk with the sole purpose of building the libsming.a library (it is not, itself, a Component)
  4. Drive the build entirely via Makefile-app.mk
  5. As @aemseemann suggests, Arduino libraries will be built separately. I guess these can go with the other libraries, unless there's a reason to keep them separate from the other libs.

It will provide some useful benefits:

  1. The build is driven entirely from the application directory. We won't have to keep swapping to the Sming directory to rebuilt the framework, change settings, etc.
  2. Eliminates the current duplication and sync. issues with app/sming makefiles
  3. Components aren't confined to the same compiler settings, but can adjusted if required
  4. We can remove STRICT as the Sming framework will always build using this setting.
  5. Producing multiple libraries will simplify linking and reduce the amount of re-compilation required
  6. Changing options won't require a rebuild of the entire library, just the relevant components. (and of course CMake can handle those dependencies automatically)
  7. Porting to CMake will be easier:
    • The main makefiles will be considerably smaller
    • Individual component.mk files will be have a direct CMake equivalent (both IDF and LWIP build systems do this)
  8. Using sub-makes we might even get parallel building to work properly!

Some other side-effects:

Looking ahead to the ESP32 arch, we will have a set of libraries which together represent the Sming framework and the user's application. The Sming build system can pass these to the IDF to include in its own build. It should be simpler than the other platforms as we can get the IDF to deal with all the detail (flashing, etc). One complication I suppose is how we deal with dependencies between Sming (or a Sming Component) and IDF components. I'm sure that will all come out in the wash, though.

Any thoughts? Do the CMake guys reckon this will help their job?

aemseemann commented 5 years ago

Hello @mikee47, your plan sounds like a big improvement to Sming's current build process and is in many aspects close to what I did on my cmake branch, so I greatly appreciate this direction. Can't wait until I can finally forget to change to the Sming directory and issue a separate 'make' command every time I touched one of Sming's source files. Also, with CMake, libsming.a & Co. would not even end up in the compiler/lib, so the Sming repository stays completely clean and can be referenced from multiple projects with different configuration options.

Two remarks to your earlier comment regarding SUBMODULES:

  1. Isn't it a chicken-and-egg problem? The component.mk would belong to the submodule, so unless it is checked out properly, we wouldn't known about the submodule(s) to check out.
  2. I would prefer adding components via add_subdirectory instead of ExternalProject_Add. Not only is this the "more natural way" with CMake, but it also allows to view and explore the whole project structure in an IDE and enjoy auto completion/symbol following for all parts of the code base (I tried this in Qt Creator with CMake server mode and was quite surprised how well it is working ootb). As a side note, in my approach, I use ExternalProject to build the host tools, because CMake can only handle one architecture per build directory. However, I am not sure if this is working on purpose, or if the CMake devs simply forgot to propagate the toolchain information down to ExternalProject :worried:

Another unrelated Idea: How about linking the build architecture to the toolchain file? In the Makefiles we have SMING_ARCH, but in CMake, it makes no sense to offer an architecture selection when we already known that the xtensa-lx106-elf toolchain is going to be used. Same is true for the xtensa-esp32-elf toolchain. Similarily, a native build (no toolchain file) would automatically select host emulation.

Overall, I think I follow @frankdownunder and keep calm while the repo reorganization is underway. In the meantime, I'll have a closer look at how ESP32/IDF handles things with CMake. I never used ESP32 before, simply because it is a total overkill for my tiny projects. Now waiting for the toolchain to build...

riban-bw commented 5 years ago

Does this approach mean that each new app would rebuild libsming.a or would you still be able to reference a common libsming.a?

mikee47 commented 5 years ago

Does this approach mean that each new app would rebuild libsming.a or would you still be able to reference a common libsming.a?

Excellent question!

So far there has been no proposal to change this behaviour, so all the libraries built as part of Sming would still be referenced.

Breaking Sming up into individual libraries helps, but I don't think it's ever going to solve the fundamental issue of those libraries being out of step with a project's requirements. Tagging each library with the options used to create it is a possible solution, but if there are more than say 2 or 3 options this could get very unwieldy.

The ESP32 IDF takes the other approach and rebuilds the entire library and all related components for each application, with all the build files in the project directory. This guarantees that all settings for a project are handled correctly, but of course it increases disk usage, extends build time, etc.

Maybe it's time to change?

mikee47 commented 5 years ago

@aemseemann Thanks for your support, much appreciated. To address your points:

Isn't it a chicken-and-egg problem? The component.mk would belong to the submodule, so unless it is checked out properly, we wouldn't known about the submodule(s) to check out. ... add_subdirectory instead of ExternalProject_Add.

It's actually the reverse, the submodule belongs to the Component (note distinction from the IDF component, un-capitalised) which is part of the Sming repo. As a rule, external dependencies are only pulled into the source tree when required by a component. Consider that if we're building for the Esp8266 we don't want to spend time cluttering the tree up with all the stuff for Host or Esp32.

I mentioned ExternalProject_Add as it seems to be the recommended way to pull in external dependencies, and not just from a GIT submodule but from ZIP files. See Arch/Host/Components/lwip/Windows/CMakeLists.txt for how I used it, much more elegant than the clunky, hand-crafted stuff it replaced! It also provides hash verification - awesome! I would welcome your feedback on how I've done this, especially in light of your point about toolchains vs. SMING_ARCH. Whilst SMING_ARCH=Host, the source tree is different depending on the toolchain (Linux or Windows). Is there a better way to do it?

It seems one of the 'features' of CMake is that there are many different ways to achieve the same thing, so establishing a standard practice will, I think, be an important part of the CMake development.

Sming as a component ?

Now I know I said above that the libsming.a library "is not, itself, a Component", but actually there is nothing special about it. In fact, building it as just another Component would simplify the build quite a bit. Consider:

CURRENT                      RESTRUCTURED
-------                      ------------

|_ Sming                      |_ Components
    component.mk
    |_ Arch                      |_ sming
                                     component.mk
    |_ Core                          |_ Arch
    |_ Platform                      |_ Core
    |_ Services                      |_ Platform
    |_ System                        |_ Services
    |_ Wiring                        |_ System
    |_ Components                    |_ Wiring
        |_ .patches              |_ .patches
        |_ http-parser           |_ http-parser
        |_ libb64                |_ libb64
        |_ libyuarel             |_ libyuarel
        |_ mqtt-codec            |_ mqtt-codec
        |_ spiffs                |_ spiffs
        |_ ws_parser             |_ ws_parser

The restructure isn't required to build Sming as a component - in fact it means we end up with nested Components so probably isn't a good idea - but should serve to illustrate the point. Thoughts?

NB. We'd also no longer require MODULES in the makefiles.

slaff commented 5 years ago

This does mean we end up with nested Components... Thoughts?

Better not for the moment. Sming should be clearly visible and not one of the many components hidden somewhere.

mikee47 commented 5 years ago

Re. shared libraries or rebuild for each application?

The nub of the problem appears to be:

a. The need to avoid re-building libraries for every application, and b. Ensuring the libraries being used were built with the same options the application is requesting

We can do this using a slightly revised dependency caching mechanism:

  1. Sming libraries will continue to be built in Sming/out/build, but a manifest file will be added for each listing the build options used
  2. The library + manifest are copied to the application directory
  3. When the application is built, check for a local copy of the library, and that the manifest matches the required options.
  4. If necessary, repeat the check in Sming/out/build. If we get a match there, take a copy, otherwise rebuild the library as per (1) and (2)

We'd also cache both debug/release builds in separate directories (rather than modifying filenames).

Because this is done on a library-by-library basis, we'll only need to rebuild those libraries whose options have changed. (Very simple libraries will have an empty manifest.)

This feels like a problem which may have already have been addressed somewhere. Anyone?

aemseemann commented 5 years ago

Re Re shared libraries or rebuild for each application?

I don't think a shared libsming is really an option with CMake. While it is technically possible to do in-source builds, it should be generally avoided. And even then, the in-source build directory could only belong to one CMake project at a time, which completely defeats the purpose. Just to have mentioned it: One could in principle build each component as a separate CMake project, install it in a common location and then use a mixture of FindPackage and exported targets to combine them to the final application. However, after having suffered from all the drawbacks of this approach at work, I would not recommend it at all.

We should however discuss which of the following use cases we wish to support:

@mikee47: What you propose about keeping multiple Sming versions with manifests in a shared location sounds like a job for a package manager/artifactory, e. g. conan. However, I am not convinced that such complication is necessary or the average user would benefit much from it. From my experience, Sming build times are quite insignificant, especially when factoring in parallel builds and moving optional components to separate libraries that are only built when referenced explicitly. (Even now, a full rebuild takes less than 2 minutes on my anchient core2duo)

And regarding ExternalProject: I think it is perfect for

Note that If you simply want to fetch and verify sources in various ways, there is FetchContent, which uses routines from ExternalProject under the hood. I'll have a look at Arch/Host/Components/lwip/Windows/CMakeLists.txt and comment on it shortly.

Edit: Your CMakeLists.txt looks mostly fine to me. Couldn't test it though, since I currently have no Windows machine at my disposal.

aemseemann commented 5 years ago

I had a look at IDFs CMake-based build system and, well, have some mixed feelings...

On one side, it is quite an ingenious build system - clean design and well structured coding. The people over at Espressif definitely have done a great job. I also like their attention to detail, e. g. offering a way to include binary ressources.

On the other hand, I would not really consider their system a CMake-based build system. It's more like a build system built on top of CMake. For example, they do their own dependency management to resolve inter-component dependencies (by "pre-processing" the components' CMakeLists.txt in a "stubbed" version of the build system in order to squeeze out the dependency information). I don't really understand the advantage over CMake's built-in dependency management with explicit calls to target_link_libraries or add_dependencies (Maybe someone else has more insight?). Also, the link step seems rather unusual to me. Since every component is a (static) library, I would have expected a bunch of target_link_libraries calls. Instead, their system generates a custom linker script that specifies all the libraries to link to the application image. In addition, they create file-level dependencies on all the *.a files to trigger relinking on any library change.

When following the 'IDF' approach, we would have to first make it work with the ESP8266 (or wait until Espressif has done it). When using a more traditional CMake-based approach, the integration into the IDF framework for ESP32 might be more challenging (Maybe expose sming+user app as the 'main' component to the IDF framework?). Nevertheless, a more traditional CMake-based approach would be my preference, mainly because I generally try to use tools (CMake) the way their creators have designed them to. In addition, I would consider it as a plus that users only have to learn about CMake (or leverage preexisting knowledge) instead of CMake + IDF if they have unusual requirements that the build system cannot fulfil out of the box.

Overall, its a tough question how to proceed. What are your thoughts?

frankdownunder commented 5 years ago

I too have mixed feelings about IDF

On the plus side, it is quite easy to set up – essentially you just have to set a list of source files [set(COMPONENT_SRCS "main.cpp" "etc.cpp")] and not much more and you are good to go. Bringing the Arduino code was also easy. My web pages, css and js all got stored in flash via set(COMPONENT_EMBED_FILES ../index.html.gz;../core.css.gz;../script.js.gz), very nice.!

But, too much hidden away. So much logic lurking behind python. The more I studied cmake the more magic IDF all looks. So yes I agree with you, lets forge ahead with a pure cmake approach observing all the many articles on best practice.

Overall, its a tough question how to proceed. What are your thoughts? I agree.

I am aiming to submit a PR soon. It will be based on your code and it will handle the Host architecture as well. You asked how to make sure SMING_ARCH uses the correct toolchain, thats a problem Ive solved pragmatically, if we can find a better way, lets do so. Options get managed by cmake-gui. Every source file is named individually rather than using a globbing technique, Ive read that cmake handles the dependencies better apparently. A single library will be created – libsming.a, we can break it up into components down the track when Mikes refactoring is done and dusted

I want to avoid submitting a PR prematurely - it needs to work, if only in a limited fashion. But it would be excellent to be in a better place to collaborate.

One thing I was wondering about – is there a native Windows port of ESP8266 anywhere? Arduino itself has one in /Users/frank/AppData/Local/Arduino15/packages/esp8266/tools/xtensa-lx106-elf-gcc/1.20.0-26-gb404fb9-2/bin/xtensa-lx106-elf-g++.exe. Where do the Arduino developers get it from? Is it compatible with sming? Id really like cmake to provide an opportunity for sming developers to use Windows without the need for a linux virtual environment like WSL or mingw.

While I am at it, it would be good to have sming as a single download – it should be able I would think to use git to clone esp-open-sdk as a first step, reducing the complexity a touch. The “install” for a developer would then be just two steps; download sming and run cmake in the Basic_Blink folders

mikee47 commented 5 years ago

I've got a working build of 'modularised makefiles' to try out. It's in my repo as 'update/modularise_makefiles' branch. I've updated the building.md file with some details.

https://github.com/mikee47/Sming/tree/update/modularise_makefiles

mikee47 commented 5 years ago

is there a native Windows port of ESP8266 anywhere? Arduino

https://github.com/earlephilhower/esp-quick-toolchain

aemseemann commented 5 years ago

@frankdownunder: sounds great. Let me know if I can support you in any way. I agree that we need some kind of a working draft. Otherwise, it is quite difficult to collaborate. How about a portable (i. e. no hard-coded paths etc.) build of libsming with a minimal set of Components (e. g. no axtls, lwip-open) as initial milestone? From there, we could try work in parallel (via PRs to your branch, if you like) to add support for the remaining components, the app image generation, do local cleanups, etc.

For an upstream PR, I think the branch should be able to build and run some of the core example (unless an earlier 'technology preview' is desired).

aemseemann commented 5 years ago

Regarding the development setup on Windows, the set of tools I would aim for is

Further tools would depend on the selected cmake generator, i. e. (mingw-)make, Eclipse, qtcreator, etc. An external SDK is optional.

If using spiffs, a host compiler is needed to build spiffy. While I suspect most developers will have a suitable compiler installed already, it shouldn't be too hard to convert this tool to python.

In the long run, I would try to get rid of the esptool2 dependency. Apparently, esptool can generate rboot-compatible images, too. And the stage2a-to-header conversion during the rboot build process could be performed by a combination of cmake and objcopy instead.

mikee47 commented 5 years ago

If using spiffs, a host compiler is needed to build spiffy. While I suspect most developers will have a suitable compiler installed already, it shouldn't be too hard to convert this tool to python.

The IDF uses a tool called spiffsgen.py, in the spiffs component :-)

aemseemann commented 5 years ago

Cool, one problem solved already!

frankdownunder commented 5 years ago

@aemseemann Did you notice that Mike has refactored the makefiles? It is no longer the case that the sming library gets built separately. Indeed, its name includes a hash of all the configuration options, which avoids the problem of a mismatch and strange behaviour as a result of building the library with different options to the project code. So the cmake approach should change too, and I will start working on that. Any thoughts?

aemseemann commented 5 years ago

Thanks @frankdownunder for the hint. I haven't noticed yet, got distracted with another projects the last couple of weeks. I've given it a try now and it works like a charm. It certainly solves the most pressing issue of a unified sming+app build process that is also aware of config settings. I also like the hashing approach. Reminds me of conan's package IDs.

Are you planning to use a similar Components-based approach with CMake?

Otherwise, I don't see why this latest refactoring should have much impact on the cmake approach. A unified build + automatic rebuilding when config settings change is already a builtin CMake feature. What would be different though is that CMake builds both the app and the Sming part in the same build directory, whereas the Makefiles always put the Sming part somewhere into $(SMING_HOME)/out/. As a consequence, sharing of build artifacts between projects (with the same settings) would not be possible using CMake.

kxygk commented 5 years ago

Wow, I'm glad I stumbled on this issue. I was just about to bring out my ESP out of the drawer to do a little project. Wish i saw this half a year ago

would prefer adding components via add_subdirectory instead of ExternalProject_Add

So I still need to dig into your setups, but I've got quite a lot of CMake experience under my belt and I just want to chime in that both add_subdirectory and ExternalProject_Add are actually very flawed

I did a write up ages ago that explains the drawbacks of both solutions (it's in the first few sections): https://geokon-gh.github.io/hunterintro.html

The add_subdirectory is general the lesser evil and I actually setup a bluepill build environment last year using just that..

But actually the superior solution is ultimately a CMake tool called Hunter (it runs from withing the CMake file itself, so you don't need to install anything). It gives you a very clean and tool-agnostic setup, but it's not as braindead simple as just slapping down a subdirectory. When it comes to robustness and reproducibility it's much better though

Last time I tried to set up CMake with the ESP build environment I really fell flat on my face though :) This is really cool you guys are shooting to set this up! I'm going to try to look over your CMake setups a bit in the coming week and see if I can contribute in any way

kxygk commented 4 years ago

https://github.com/frankdownunder/Sming/blob/feature/cmake/Sming/CMakeLists.txt

This whole thing is looking really cool! The only thing I'd suggest is modularizing it more. In my humble opinion it's just trying to do way too much all at once. Here are my immediate thoughts.. please take it with a grain of salt

There is a lot of stuff I'm really ignorant about - like how Arduino libs gets built and linked, why GDB (and other) flags are going through custom #defines and some other stuff.. So I'm not gunna say anything about that stuff and end up having egg on my face because I don't understand it :P

I definitely don't want to step on any toes here - but let me know if you're interested in pull requests @frankdownunder or anything else. I'll try to help how I can if you want :)

paulbendixen commented 4 years ago

Looks very impressive Regarding the toolchain file, depending on how old a CMake you want to support, you should probably go with setting CMAKE_TRY_COMPILE_TARGET to STATIC_LIBRARY. I've also had a lot of success using find program to set the toolchain file

find_program( CMAKE_C_COMPILER
    xtensa-lx106-elf-gcc
    HINTS ${ESP_HOME}xtensa-lx106-elf/bin/
    DOC "The esp8266 C compiler"
)

Also I believe you need to set the CMAKE_TOOLCHAIN_FILE before the first call to project in order for it to have any effect

kxygk commented 4 years ago

My understanding is that the toolchains file is only ever set from outside the project when cmake is run

cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/toolchains/file 

I understand it doesn't look very ergonomic, but I've only ever see it used that way - where the developer points to which toolchain he wishes to use for a specific configuration

Then (on a Linux system at least) you can continue editing source files and rerunning make in the build directory and the toolchain will remain as whatever was configured for that build directory (you can have many different build directories with different configurations that way and one common source directory)

paulbendixen commented 4 years ago

I believe you are right, (sadly) but it is still set in the CMakeLists.txt and will probably not work. It should probably be removed.

frankdownunder commented 4 years ago

With version 4 released, much of the "dust" has settled, so now would be a good time to revisit the cmake approach. However, I was recently diagnosed with MSA so I have to pull back from doing this. I will try to contribute where I can.

0smr commented 3 months ago

Hi, I was curious about how this has gone so far. Does SMING currently support CMake? If yes, are there any examples of how to use it with CMake?