Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using PSTR and PROGMEM string with template class causes section type conflict #3369

Closed
sticilface opened this issue Jun 23, 2017 · 4 comments

Comments

@sticilface
Copy link
Contributor

Using latest git and arduino IDE.

I use PROGMEM strings and a debug define that places debug messages into progmem, however this does not seem to work when combined with templated classes.

The error is the same as this issue: #2078

i define my debug as

#define DEBUG(_1, ...) { TEST.printf_P( PSTR(_1) ,##__VA_ARGS__); }

and a const char as

const char testString[] PROGMEM = "Test String"; 

Individually they both compile. i.e. if the debug define is enabled but i do not use testString. it works, and vice versa. but if i use both

In file included from /Users/amelvin/Documents/Arduino/templatesketch/templatesketch.ino:2:0:
test.h:7: error: testString causes a section type conflict with __c
 const char testString[] PROGMEM = "Test String"; 
            ^
In file included from /Applications/Arduino.app/Contents/Java/hardware/esp8266com/esp8266/cores/esp8266/Arduino.h:240:0,
                 from /var/folders/nv/8j3v5v0s18v7p4249kv8qbz80000gq/T/arduino_build_216642/sketch/templatesketch.ino.cpp:1:
/Applications/Arduino.app/Contents/Java/hardware/esp8266com/esp8266/cores/esp8266/pgmspace.h:21:51: note: '__c' was declared here
 #define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))
                                                   ^
/var/folders/nv/8j3v5v0s18v7p4249kv8qbz80000gq/T/arduino_build_216642/sketch/test.h:11:41: note: in expansion of macro 'PSTR'
 #define DEBUG(_1, ...) { TEST.printf_P( PSTR(_1) ,##__VA_ARGS__); }
                                         ^
/var/folders/nv/8j3v5v0s18v7p4249kv8qbz80000gq/T/arduino_build_216642/sketch/test.hpp:5:3: note: in expansion of macro 'DEBUG'
   DEBUG("abc");
   ^
exit status 1
testString causes a section type conflict with __c

A full working example can be found here
https://gist.github.com/sticilface/9a6410978d7235a469c1e154c1c4c396

@igrr
Copy link
Member

igrr commented Jun 23, 2017

#2078
#3351

@sticilface
Copy link
Contributor Author

I found the first one, but I'm not sure i follow. As long as i don't use the debug define it works. so it can link even when the progmem is used inside a templated class. or is that where the second one enters the picture and you can't use PROGMEM and FPSTR inside same file?

@sticilface
Copy link
Contributor Author

Ok got it to work. Need to move the implementation of the PROGMEM string from the .h file to a .cpp file, and extern it in the header. Then it compiles fine.

in .h:

namespace ESPmanagerinternals {
extern const char key_networks[]; 
}

in .cpp

const char ESPmanagerinternals::key_networks[] PROGMEM = "networks";

@Adam5Wu
Copy link
Contributor

Adam5Wu commented Mar 1, 2018

I have recently encountered this problem and I may have a solution. 😄

Background

The background of my issue is that, I have been using custom debug logging macros, something like:

DEBUG_LOG("Blah blah %d ...", ValueX);

I have so many of them and the string literals starts to eat up the RAM, obviously transit to PROGMEM is the solution.
And I want to leverage on my use of logging macro to reduce the effort, by converting:

#define DEBUG_LOG(...) Serial.printf(__VA_ARGS__)

to

#define DEBUG_LOG(fmt, ...) \
{ static const char pfmt[] PROGMEM = fmt; Serial.printf_P(pfmt, ## __VA_ARGS__); }

And I encountered the infamous error "pfmt causes a section type conflict with pfmt", because I have debug logs in both "regular" functions and template functions.

The solution of extracting each and every log string into a global static variable is not acceptable to me - not only too much transitional effort, but also increase the maintenance overhead and reduce the usability. (Imagine the scenario you see a debug log line, and wants to look at the relevant code. With inline string you just do a single search. With extracted variable, you first find the variable, and you have to search the variable name again to locate the source...)

Reasoning

The post here gave me an idea of the root cause, and then I dug out "eagle.app.v6.common.ld" with an interesting line:

.irom0.text : ALIGN(4)
{
...
    *(.irom0.literal .irom.literal .irom.text.literal .irom0.text .irom.text .irom.text.*)
...
}

The .irom.text.* gave me an idea:

  • According to this document, PROGMEM translates to ICACHE_RODATA_ATTR translates to __attribute__((section(".irom.text")))
  • Of course, it is a conflict to merge into a single section from template code with GROUP attribute and non-template code without GROUP attribute
  • What if I define a new section, say .irom.text.template to hold all flash strings from template code?
    • First, there should not be any conflict
    • Second, this section will be put into flash because of the .irom.text.* specification

Solution

So I tried the following:

#define PROGMEM_T __attribute__((section(".irom.text.template")))
#define DEBUG_LOG_T(fmt, ...) \
{ static const char pfmt[] PROGMEM_T = fmt; Serial.printf_P(pfmt, ## __VA_ARGS__); }

And for all debug log states in template method I switched from:

DEBUG_LOG("Blah blah %d ...", ValueX);

to

DEBUG_LOG_T("Blah blah %d ...", ValueX);

And the code compiles and runs perfectly fine! 😆
It is still a little more work than just changing the macro, but with a reasonable cost, at least it allows to use inline flash string in log statements.

earlephilhower added a commit to earlephilhower/Arduino that referenced this issue Dec 9, 2018
The bug referenced in the code that required a custom macro to enable
PSTR/PROGMEM compilation ( esp8266#3369 )
was fixed a while back and all PROGMEM references now live in their own
save .sections.

This patch simply is the output of `sed -i s/PSTR_LEA/PSTR/g *` and
`sed -i s/PROGMEM_LEA/PROGMEM/g *` on the codebase and the removal
of those defines.
devyte pushed a commit that referenced this issue Dec 9, 2018
The bug referenced in the code that required a custom macro to enable
PSTR/PROGMEM compilation ( #3369 )
was fixed a while back and all PROGMEM references now live in their own
save .sections.

This patch simply is the output of `sed -i s/PSTR_LEA/PSTR/g *` and
`sed -i s/PROGMEM_LEA/PROGMEM/g *` on the codebase and the removal
of those defines.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants