romeric/Fastor

Compiling Fastor for Esp32 microcontroller using PlatformIO, gcc 8 and c++17

Apocalyt opened this issue · 7 comments

Hi,
I have been looking for a linear algebra library I could use to develop some Kalman filters with and getting a workflow and libraries going, where I could share most of the used code for embedded and PC platforms by using header only libraries and templatized classes. My idea has been to inject all platform specific implementations to more generic code via template parameters. This would allow me to pretty seamlessly go between PC and MC during algorithm and application development.

This in mind I have now tried to compile Fastor with PlatformIO for native build and Esp32. I encountered some issues, which I were able to work around one way or another to get Fastor to compile with some basic examples on Esp32 and Linux PC. I was thinking of sharing these problems and wondered whether you would be interested in making or taking in some possible changes in the future to make the build process easier with PlatformIO and on MC platforms? I don't (yet) have proper solutions for all of these problems and some of them are not really problems with Fastor itself, but I though they would be good to share anyway.


The first problem I encountered was that when using PlatformIO to try and automatically install your library for my PC -build by adding the git URL to my platformio.ini -file, the include paths would not work. To explain this a bit PlatformIO offers a functionality to automatically install libraries to standard project location based on just a git repository URL. My current PlatformIO -file has lines like this for example:

lib_deps =
  https://github.com/Apocalyt/lever.git#master
  https://github.com/Apocalyt/Fastor.git#version/V0.6.3

Libraries need to provide a library.json -file (https://docs.platformio.org/en/latest/librarymanager/config.html) to be easily installable with PlatformIO, but it seems that PlatformIO can also try to generate it automatically.
The include paths were wrong because PlatformIO didn't generate the library.json -file to Fastor repository root, but under the root/Fastor -directory and discard everything not in this directory. This would otherwise be fine, but now include paths containing Fastor/<PATH_TO_FILE> should not have the Fastor -folder at the start. This results in following failure:

.pio/libdeps/native/Fastor/config/config.h:439:10: fatal error: Fastor/config/macros.h: No such file or directory
  439 | #include "Fastor/config/macros.h"

I fixed this by adding a dummy library.json file to Fastor repository root: https://github.com/Apocalyt/Fastor/blob/version/V0.6.3/library.json
This makes PlatformIO take in the whole library from root directory onward and include is working now.


The second problem resulting from this was that PlatformIO now tried to build the benchmarks, since the benchmark -forder was included too. This resulted in following compilation problem among others:

.pio/libdeps/native/Fastor/benchmark/benchmark_academic/crossproduct_backend/benchmark_cofactor_backend.cpp: In function ‘void iterate_over_fastor_cross(const T*, T*)’:
.pio/libdeps/native/Fastor/benchmark/benchmark_academic/crossproduct_backend/benchmark_cofactor_backend.cpp:63:25: error: ‘PlaneStrain’ was not declared in this scope
   63 |         _crossproduct<T,PlaneStrain>(a,a,out);

I don't really know why these failed to compile, but I just removed the whole benchmarks folder as a workaround:


Next I needed to disable my -Werror -option, since I received some warnings:

.pio/libdeps/native/Fastor/Fastor/tensor_algebra/permute.h:273:15: warning: typedef ‘using resulting_index = typename _permute_impl::resulting_index’ locally defined but not used [-Wunused-local-typedefs]
.pio/libdeps/native/Fastor/Fastor/util/extended_algorithms.h:70:49: warning: unused parameter ‘is_signed’ [-Wunused-parameter]
.pio/libdeps/native/Fastor/Fastor/util/extended_algorithms.h:70:49: warning: unused parameter ‘is_signed’ [-Wunused-parameter]

With these I was able to compile and install on PC using PlatformIO just by adding the URL to my modified fork: https://github.com/Apocalyt/Fastor/tree/version/V0.6.3

When continuing to compile for Esp32 I hit the next issue. It is not a good idea to enable RTTI for this kind of platform with small amount of flash available. All the code does get automatically built with "-fno-rtti" and therefore typeid() -function won't compile.
It is used in this file here: /Fastor/util/types.h
I solved this problem by commenting out the code and always returning default string.

I suppose this is only needed for some debug purpose? Would it be possible to allow compiling the library with "-fno-rtti" somehow, without a need to comment out the code.


The next issue I encountered was that Fastor apparently attempts to change stack size on some situations.
I had to turn this function into a dummy, since rlim_t was not found.

#ifndef _WIN32
inline size_t set_stack_size(size_t size) {
    // If the function does not work, copy-paste it within
    // the body of the main

    // size is stack size in MB (for instance provide 80 for 80MB)
    // returns old stack size in MB
    const rlim_t stacksize = size*1024*1024;
    struct rlimit rl;
    int result;
    result = getrlimit(RLIMIT_STACK, &rl);
    rlim_t old = rl.rlim_cur = stacksize;
    if (result==0) {
        if (rl.rlim_cur < stacksize) {
            rl.rlim_cur = stacksize;
            result = setrlimit(RLIMIT_STACK,&rl);
            FASTOR_ASSERT(result !=0, "CHANGING STACK SIZE FAILED");
        }
    }

    return old;
}
#endif

Then is this functionality needed? In many MCs stack sizes are usually set to a fixed size big enough to run the specific application. It may not be possible to change stack size at all during runtime and Linux system command won't work, since there is no Linux installed.


The last problem I encountered was actually to an irresponsible use of briefly named macro -definitions in Arduino framework support library code, conflicting with variable names in Fastor.

I had to add this before including Fastor to get rid of the conflicts:

#undef B00
#undef B01
#undef B10
#undef B11
#undef B1
#include <Fastor/Fastor.h>

Without these I received errors like this:

In file included from /home/apocalyt/.platformio/packages/framework-arduinoespressif32/cores/esp32/Arduino.h:40,
                 from include/hardware_implementations/digital_pin_implementation.h:5,
                 from src/main.cpp:1:
.pio/libdeps/nodemcu-32s/Fastor/Fastor/backend/tensor_cross.h: In function 'void Fastor::_crossproduct(const T*, const T*, T*)':
/home/apocalyt/.platformio/packages/framework-arduinoespressif32/cores/esp32/binary.h:24:13: error: expected unqualified-id before numeric constant
 #define B00 0
             ^
.pio/libdeps/nodemcu-32s/Fastor/Fastor/backend/tensor_cross.h:42:7: note: in expansion of macro 'B00'

The good new was that after these changes the code succesfuly compiled on Esp32 and I was able to calculate same basic math with it. What do you think? Do you have any ideas what could be done to make this kind of workflow easier or interest in taking some changes in if I come up with something?

Sorry for such a long post.

Thanks for such a detailed report. This sounds quite promising. It would be great to be able to run Fastor on microcontrollers out-of-the-box. I can see that the issues that you're currently having are pretty minor and can be fixed easily. I'll push some changes ASAP to fix some of these.

In the meantime given that you're the one who's testing please feel free to submit your PRs.

With regards to the json file, is it possible to add an entry there to ignore building certain directories? The benchmark directory has external code so you most definitely want to skip that. Also we change stack size for running certain benchmarks but not internally in Fastor.

Some initial fixes pushed here 0ffedbc.

Thanks for you answer and also making some initial fixes already.
I don't think ignoring directories is easily possible with just library.json, but I will see what I can find out about that.
Just removing the benchmarks obviously isn't a real workable solution :)

I guess I have fixed all of your issues that you have mentioned here including the json file and compiling Fastor with no rtti. Please clone the latest version of Fastor. I am closing this issue. If you still have issues, let me know/reopen.

I had some time to do some testing now and wow, you did excellent work with this. Thanks a lot.
The version in the master branch does still produce a few warning, if I use GCC with -Wall, but all the bigger issues have been fixed, as you mentioned.

I noticed that you had added the exclude directory definition to the library.json -file.
What I found out about that is that, they are not used in current PlatformIO version, when I use a direct git URL, to point to a library. I wonder, whether PlatformIO -would be willing to add the capability to use these even when linking directly to a git -repository URL.

However, they are used if one were to want and register a library release to the PlatformIO registry: https://platformio.org/lib
or use the PlatformIO command "pio package pack Fastor/", which produces a tar -file, which would be added to the said registry.
The PlatformIO registry allows user to search for and easily install libraries to use in their projects (MC or native projects).
I am quite happy with the current state as I am able to now do "pio package pack Fastor/", add the ouputfile to my platformio.ini -file and then use Fastor on Linux and Esp32.

Now if you wanted, you could now easily add Fastor to the registry where it would be easily searchable and installable to PlatformIO users in quite large collection of different platforms, by running the package publish command when doing a new release, since you have a working library.json -file in there now: https://docs.platformio.org/en/latest/core/userguide/package/cmd_publish.html#cmd-package-publish

Great stuff. I have published Fastor on PlatformIO now https://platformio.org/lib/show/11298/Fastor

Thanks a lot. This removes the need for me to do the manual "pio package pack" and I can directly refer to the library by name and use it :)