PlatformIO Community

The command line is too long

I’m creating a certificate in python using openssl and I’m trying to assign it to a variable that I will import in my main.cpp.

In python I append an env var like this:

env.Append(BUILD_FLAGS=['\'-DCERTIFICATE="'+key+'"\''])

where the “key” var is a string.
The problem is that the string is quite long, and if I try to build my project with platformio run, at some point during the build process I get the error “the command line is too long”.

If I use a shorter string, everything gets compiled successfully.

Any ideas on how to solve this problem? Is it a platformio bug, an OS limit, or just me using a bad practice?
I’m using Windows 10.

platform = espressif32
board = az-delivery-devkit-v4
framework = arduino
extra_scripts = 
  pre:python-scripts/createCertificate.py
[...]

Nope.

Yes, Windows (10 and prior) legacy limitation. Refer to https://github.com/platformio/platformio-core/issues/2877#issuecomment-518849464 and Linker "The command line is too long" (ESP32).

Passing an extremely long string / certificate file content as a macro is indeed… weird.

If you’re using an ESP32, why not just put your certificate file into the data/ folder and use the SPIFFS filesystem? Then you can just put the cert files verbatim in the data/ folder and read them in your firmware from the normal file system. See docs on https://docs.platformio.org/en/latest/platforms/espressif32.html#uploading-files-to-file-system-spiffs and the example at https://github.com/espressif/arduino-esp32/blob/master/libraries/SPIFFS/examples/SPIFFS_Test/SPIFFS_Test.ino.

If you don’t want to use a filesystem but really want to embed the string in compile time, just use the feature that is made exactly for that: Embedding binary data.

Adding directives like

board_build.embed_txtfiles =
  src/certificate.pem.crt

will include the content of the src/certificate.pem.crt at compile-time into special symbols. In C++ code you can then add

/* start pointer */
extern const uint8_t certificate_pem_crt_start[] asm("_binary_src_certificate_pem_crt_start");
/* end pointer */
extern const uint8_t certificate_pem_crt_end[] asm("_binary_src_certificate_pem_crt_end");

void some_func() {
   //re-cast to const char*. Assumes string is null-terminated!! 
   //otherwise calculate length by doing len = end - start + 1.
   const char* cert_string = (const char*) certificate_pem_cert_start;
   //do something.. 
}

If your Python script is dynamically generating the certificate you’d need to rewrite to generate the certificate.pem.crt that is about to be embedded, as the first action in the build process.

Of course, other self-made methods like generating a .h and .cpp files from the Python script in which your certificate is embedded also work.

cert.h

#ifndef MY_CERT_H
#define MY_CERT_H

#include <stdint.h>
#include <stddef.h>

// or uint8_t if general byte content and not ascii-string
extern const char certificate_content[];
extern size_t certificate_length;

#endif

cert.cpp

#include "cert.h"

const char certificate_content[] = <auto-generated certificate string here>; 
size_t certificate_length = <length>;

Wow, now everything makes sense! Thanks!