Page 1 of 1

compiling c structs in c++ program

Posted: Mon Mar 18, 2019 12:09 am
by wegunterjr
I am getting the following warning which results in a compile error:
sorry, unimplemented: non-trivial designated initializers not supported
I am trying to initialize a struct for doing an OTA..

Code: Select all

  esp_tls_cfg_t cfg = {
.cacert_pem_buf = (const unsigned char *)aws_root_ca_pem,
.cacert_pem_bytes = (unsigned int)(strlen(aws_root_ca_pem)+1),
         .non_block = true,
            .alpn_protos = "\x02h2",
};

Re: compiling c structs in c++ program

Posted: Mon Mar 18, 2019 1:04 am
by ESP_Angus
C++ doesn't support C99-style named initializers for structs, and g++ (the C++ compiler we use) doesn't support any way to enable them as an optional extra.

You have three alternatives:
  • Order the elements in the named initializer in the same order they're declared in the struct. The C++ compiler should allow this.
  • Move code which initializes structs to a .c file, and call the .c file from your .cpp code.
  • Rewrite to individually initialize each element, something like:

    Code: Select all

    esp_tls_cfg_t cfg = { }; // note: brackets are important to zero-initialize the structure
    strlcpy(cfg.cacert_pem_buf, aws_root_ca_pem, sizeof(cfg.cacert_pem_buf));
    cfg.cacert_pem_bytes = strlen(aws_root_ca_pem)+1;
    cfg.non_block = true;
    
    static const char *proto = "h2";
    static const char *protos[] = { proto, NULL };
    cfg.alpn_protos = protos;
    
    (Compiler should optimize this to the same code as the C99 initializer, anyhow.)
Note: I changed the alpn_protos format here because I think this is actually the correct format, despite what the docs say. I'm going to check this with the ESP_TLS and HTTP/2 developers, but maybe what you had is actually correct in which case please change it back.

Re: compiling c structs in c++ program

Posted: Mon Mar 18, 2019 4:05 am
by wegunterjr
Thanks for the help. I did try something similar as 3 and what you've shown there, but went ahead and tried what you suggested...
I am getting this error:

Code: Select all

error: invalid conversion from 'const unsigned char*' to 'char*' [-fpermissive]
for this line:

Code: Select all

	esp_tls_cfg_t cfg = { }; // note: brackets are important to zero-initialize the structure
	strlcpy(cfg.cacert_pem_buf, aws_root_ca_pem, sizeof(cfg.cacert_pem_buf));
and still getting the error about the bytes being read only...which is strange.

Code: Select all

error: assignment of read-only member 'esp_tls_cfg::cacert_pem_bytes'

Re: compiling c structs in c++ program

Posted: Mon Mar 18, 2019 4:50 am
by ESP_Angus
Ah my mistake, this is a "const unsigned char *" not an array in the structure.
https://docs.espressif.com/projects/esp ... t_pem_bufE

Something like this should work:

Code: Select all

cfg.cacert_pem_buf = (const unsigned char *)aws_root_ca_pem;
(If there's any chance that aws_root_ca_pem pointer may become invalid during the life of the ESP_TLS config, you'll need to copy it into a static or other buffer first and then cacert_pem_buf to point to that buffer.)

Re: compiling c structs in c++ program

Posted: Mon Mar 18, 2019 5:25 am
by wegunterjr
alright, tried that too...still getting the error about the bytes being read only... I am using 3.1.3 though, not 3.2 or the latest (would that be part of the problem...i tried digging into the core library, but couldn't find anything that said read only)..my struct has only 4 parts in the header...(none of them are read-only though)....
https://docs.espressif.com/projects/esp ... p_tls.html

Code: Select all

	esp_tls_cfg_t cfg = { }; // note: brackets are important to zero-initialize the structure

	cfg.cacert_pem_buf = (const unsigned char *)aws_root_ca_pem;
	cfg.cacert_pem_bytes = strlen(aws_root_ca_pem)+1;
	cfg.non_block = true;

	static const char *proto = "h2";
	static const char *protos[] = { proto, NULL };
	cfg.alpn_protos = protos;

Code: Select all

 error: assignment of read-only member 'esp_tls_cfg::cacert_pem_bytes'

Re: compiling c structs in c++ program

Posted: Mon Mar 18, 2019 5:33 am
by ESP_Angus
Right, sorry, I think this is a bug - the field is incorrectly typed as const unsigned integer not an unsigned integer. Fixed in v3.2 and newer branches, not fixed in v3.1 branch yet.

I think your options here are:

1) Initialize all the fields in order to keep the compiler happy.
2) Edit esp_tls.h and change "const unsigned int cacert_pem_bytes;" to "unsigned int cacert_pem_bytes"
or
3) Initialize this one structure in C code and reference it from c++.

Sorry again. Fix coming ASAP.

EDIT: removed bad advice.

Re: compiling c structs in c++ program

Posted: Mon Mar 18, 2019 5:43 am
by wegunterjr
woohoo..I am useful. HA!

okay..when you say at the top... do you mean at the top of my cpp file... like above main and all that?
or in the top of my ota_task before I set anything else up...

Cuz, i added this to the top of the file:

Code: Select all

esp_tls_cfg_t cfg = { .cacert_pem_bytes = strlen(aws_root_ca_pem) };
and added this in the ota_task where I am about to use it:

Code: Select all

cfg.cacert_pem_buf = (const unsigned char *)aws_root_ca_pem;
//	cfg.cacert_pem_bytes = strlen(aws_root_ca_pem)+1;
	cfg.non_block = true;

	static const char *proto = "h2";
	static const char *protos[] = { proto, NULL };
	cfg.alpn_protos = protos;
but i get the warnings that equal errors about non-trivial designated initializers....
src\main.cpp:261:67: sorry, unimplemented: non-trivial designated initializers not supported
esp_tls_cfg_t cfg = { .cacert_pem_bytes = strlen(aws_root_ca_pem) };
^
src\main.cpp:261:67: warning: missing initializer for member 'esp_tls_cfg::cacert_pem_buf' [-Wmissing-field-initializers]
src\main.cpp:261:67: warning: missing initializer for member 'esp_tls_cfg::cacert_pem_bytes' [-Wmissing-field-initializers]
src\main.cpp:261:67: warning: missing initializer for member 'esp_tls_cfg::non_block' [-Wmissing-field-initializers]

Re: compiling c structs in c++ program

Posted: Mon Mar 18, 2019 5:46 am
by ESP_Angus
Sorry, I gave you bad advice (been a while since I wrote C++). Have edited previous post, just before you replied I think. :|

One bit of good news on the horizon, when we update to gcc 8 then "non-trivial designated initializer" support is added and the original code you wrote should work (maybe after some errors about the fields being out of order.)

Re: compiling c structs in c++ program

Posted: Mon Mar 18, 2019 10:25 pm
by wegunterjr
Changing the esp_tls.h to use a unsinged int worked for me. Well, at least I can compile and it doesn't force reboot. HA!
ESP_Angus wrote:
Mon Mar 18, 2019 5:33 am
Right, sorry, I think this is a bug - the field is incorrectly typed as const unsigned integer not an unsigned integer. Fixed in v3.2 and newer branches, not fixed in v3.1 branch yet.

I think your options here are:

1) Initialize all the fields in order to keep the compiler happy.
2) Edit esp_tls.h and change "const unsigned int cacert_pem_bytes;" to "unsigned int cacert_pem_bytes"
or
3) Initialize this one structure in C code and reference it from c++.

Sorry again. Fix coming ASAP.

EDIT: removed bad advice.