I’m using visual studio code (VSC) with platformio (PIO) on Win11.
I want to use two cpp-files, one for testing (test.cpp) and one to keep working code (main.cpp).
In platformio.ini I defined two environments (one for release and one for testing):
[platformio]
extra_configs = secrets.ini ;keeping my secrets (upload_flags = --auth="myPassword"
[env]
lib_deps = myLibraries
platform = espressif32
board = az-delivery-devkit-v4
framework = arduino
monitor_speed = 115200
[env:release_ota]
extra_scripts = post:extra_script.py ;to delay after update to open telnet after wifi is established
monitor_port = socket://192.168.2.38:23
upload_protocol = espota
upload_port = 192.168.2.38
[env:test_ota]
extends = env:az-delivery-devkit-v4_ota
build_flags = -D test
In main.cpp I have this head:
#ifdef test
#include "test.cpp"
#endif
#ifndef test
my code
#endif
and in test.cpp I have this head:
// #define test // Just for VS-Code to keep code undimmed
#ifdef test
my testcode
#endif
This is compiling and uploading in env:release_ota as it should. But when I compile using env:test_ota I get the errors “multiple definition of ‘x’;” where x stands for definitions and functions defined in both cpp-files. It seems, that the preprocessor directives #ifdef and #ifndef are ignored and code of both files is compiled.
Where is my error or is my understanding of preprossor directives wrong? Thought that, depending test is defined or not, only the code of one of the two files is compiled.
If I use #define test in main.cpp compilation is running without errors, but then code in test.cpp is dimmed and code completion by intelliSense is not working.
What’s the file structure here? If both src/main.cpp and src/test.cpp exist, then the project will compile main.cpp, which includes the code from test.cpp, and test.cpp, leading to the double definition.
Thanks for your fast response.
I want, that if test is defined, the code of test.cpp is compiled, if not the code of main.cpp is compiled. But if test is defined using build_flags in platformio, I get the error
c:/users/xs400dohc/.platformio/packages/toolchain-xtensa-esp32/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: .pio\build\test_ota\src\test.cpp.o: in function `myFunction(int, int)':
D:\pathToMyProject/src/test.cpp:151: multiple definition of `myFunction(int, int)'; .pio\build\test_ota\src\main.cpp.o:D:\pathToMyProject/src/test.cpp:151: first defined here
My understanding of this error is, that in both files myFunction(int, int) is defined.
But with #ifdef test or #ifndef test compilation of one of the codes should be excluded depending if test is defined or not.
PlatformIO will by default build all source files it finds within the src/ folder. So, if src/test.cpp exists, it will be built. Same as with src/main.cpp.
The src/main.cpp does need to include the test.cpp source code. It just needs to import a header file (.h) for it, that describes all functions that the test.cpp file does have. And then only call int othem if the test` macro is activated.
You are already correctly “nulling out” the test.cpp file based on #ifdef test .. #endif. Another way to control that would be with a build_src_filter.
If platformio builds all source files in src/, why I only get the errors when I compile env:test_ota but not if I compile env:release_ota? Both files exists in src/.
But if test is defined the code of main.cpp should be ignored because of #ifndef just the same way #include "test.cpp" is ignored if test is not defined.
If test is defined you include the whole test.cpp code in main.cpp, causing those functions to be in the main.cppcompilation unit, on top test.cpp being compiled and those functions being in the test.cpp compilation unit too.
Just avoid#include <xxx.cpp>. It only creates problems like these. Just include the header file for test.cpp at that point (or create it if it has not already been created).
Just wanted to understand, why it’s not working. I hope now I got it.
So I will try to make my first .h-file. Thank you for your tolerance with a beginner like me.
Until I have build my .h-file, I found a work-around working for me:
I only use env: release_ota. In main.cpp in the first line I define test: #define test. If I comment that line, code of main.cpp is build, if uncomment code of test.cpp is build.
And for the problems with dimming and code completion by IntelliSense, I added in c_cpp_properies.json (you can get to the file by pressing ctrl+shift+p, search for C/C++: Edit Configurations (UI) and add "test" to defines like this:
"defines": [
"test"
]
But then the definition is fixed and IntelliSense is always dimming code in main.cpp and the change in c_cpp_properties.json is lost after restarting VSC.
This way is working on my computer, but shouldn’t if I understood you right.
If my asking is not to annoying: Is there a difference if I define something in build_flags or in code? If I understood build_flags the right way, build_flags -D name and #define name are equivalent (“Predefine name as a macro, with definition 1”). So that’s why I’m so persistent, because I don’t understand the difference and why '#define test is working but build_flags = -Dtest does not.
The main reason I was asking: I want IntelliSense to dim / undim the code in test.cpp depending on test is defined or not, just like in main.cpp. But I think the way I did before (#define test in test.cpp while working in test.cpp and comment it before starting the build) is more easy for me.
Finaly I made two environments:
One for testing excluding main.cpp and including test.cpp and
one for productive including main.cpp and excluding. My Platformio.ini: