Possible bug with `build_src_filter`

Hello,

I think I have stumbled upon a bug but I would like to make sure I’m not generating nonsense before creating an issue and wasting contributors’ time.

I have a test project with this structure and contents

linktest/
├─ src/
│  ├─ LinkTest.cpp
│  ├─ main.cpp
│  ├─ alt.cpp
├─ include/
│  ├─ LinkTest.h
├─ platformio.ini
// LinkTest.h
class LinkTest {
    private:
        int anInt;
    public:
        LinkTest(int a);
};
// LinkTest.cpp
#include <LinkTest.h>
LinkTest::LinkTest(int a) : anInt(a) {};
// main.cpp & alt.cpp, both files have the same content
#include <Arduino.h>
#include <LinkTest.h>

void setup() {
  LinkTest test(1);
}

void loop() {}
; platformio.ini
[env:main]
platform = atmelavr
board = nanoatmega328
framework = arduino

[env:test1]
platform = atmelavr
board = nanoatmega328
framework = arduino
build_src_filter =
	-<alt.cpp>
	+<main.cpp>

[env:test2]
platform = atmelavr
board = nanoatmega328
framework = arduino
build_src_filter =
	-<main.cpp>
	+<alt.cpp>

The linker fails when trying to use either the test1 or test2 environments with this trace:

Processing test1 (platform: atmelavr; board: nanoatmega328; framework: arduino)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/atmelavr/nanoatmega328.html
PLATFORM: Atmel AVR (4.2.0) > Arduino Nano ATmega328 
HARDWARE: ATMEGA328P 16MHz, 2KB RAM, 30KB Flash      
DEBUG: Current (avr-stub) External (avr-stub, simavr)
PACKAGES:
 - framework-arduino-avr @ 5.1.0
 - toolchain-atmelavr @ 1.70300.191015 (7.3.0)       
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 5 compatible libraries
Scanning dependencies...    
No dependencies
Building in release mode    
Compiling .pio\build\test1\src\main.cpp.o
Archiving .pio\build\test1\libFrameworkArduinoVariant.a
Compiling .pio\build\test1\FrameworkArduino\CDC.cpp.o
Compiling .pio\build\test1\FrameworkArduino\HardwareSerial.cpp.o
Compiling .pio\build\test1\FrameworkArduino\HardwareSerial0.cpp.o
Compiling .pio\build\test1\FrameworkArduino\HardwareSerial1.cpp.o
Compiling .pio\build\test1\FrameworkArduino\HardwareSerial2.cpp.o
Compiling .pio\build\test1\FrameworkArduino\HardwareSerial3.cpp.o
Compiling .pio\build\test1\FrameworkArduino\IPAddress.cpp.o
Compiling .pio\build\test1\FrameworkArduino\PluggableUSB.cpp.o
Compiling .pio\build\test1\FrameworkArduino\Print.cpp.o
Compiling .pio\build\test1\FrameworkArduino\Stream.cpp.o
Compiling .pio\build\test1\FrameworkArduino\Tone.cpp.o
Compiling .pio\build\test1\FrameworkArduino\USBCore.cpp.o
Compiling .pio\build\test1\FrameworkArduino\WInterrupts.c.o
Compiling .pio\build\test1\FrameworkArduino\WMath.cpp.o
Compiling .pio\build\test1\FrameworkArduino\WString.cpp.o
Compiling .pio\build\test1\FrameworkArduino\abi.cpp.o
Compiling .pio\build\test1\FrameworkArduino\hooks.c.o
Compiling .pio\build\test1\FrameworkArduino\main.cpp.o
Compiling .pio\build\test1\FrameworkArduino\new.cpp.o
Compiling .pio\build\test1\FrameworkArduino\wiring.c.o
Compiling .pio\build\test1\FrameworkArduino\wiring_analog.c.o
Compiling .pio\build\test1\FrameworkArduino\wiring_digital.c.o
Compiling .pio\build\test1\FrameworkArduino\wiring_pulse.S.o
Compiling .pio\build\test1\FrameworkArduino\wiring_pulse.c.o
Compiling .pio\build\test1\FrameworkArduino\wiring_shift.c.o
Archiving .pio\build\test1\libFrameworkArduino.a
Linking .pio\build\test1\firmware.elf
C:\Users\eldask\AppData\Local\Temp\ccYWOhmX.ltrans0.ltrans.o: In function `main':
<artificial>:(.text.startup+0x98): undefined reference to `LinkTest::LinkTest(int)'
collect2.exe: error: ld returned 1 exit status
*** [.pio\build\test1\firmware.elf] Error 1

I would like to know if I’m overlooking something or if this is indeed a bug related failure? Also, if I remove the contents of alt.cpp and build with the main environment, everything builds fine.

Thank you!

I’ve done a quick test with your supplied files and code.

  • pio run -e main won’t ever work as both alt.cpp and main.cpp have got setup() and loop() so duplicate references will occur.

  • pio run -e test1 compiles main.cpp but the link fails with the error you are seeing.

  • pio run -e test2 compiles alt.cpp but the link fails with the error you are seeing.

So, given the last two actually compile what you have asked, it seems that the build_src_filter is working as expected. The problem lies elsewhere.

Your LinkTest files are effectively, a library, so what I did was:

mkdir lib/LinkTest
mv src/LinkTest.* lib/LinkTest

Now, only main.cpp and alt.cpp live in src.

pio run -e test1 -e test2 gives me:

Environment    Status    Duration
-------------  --------  ------------
test1          SUCCESS   00:00:00.239
test2          SUCCESS   00:00:00.236

Also, because your main environment is never going to work, you could change your platformio.ini to the following:

; Comon settings for all environments.
[env]
platform = atmelavr
board = nanoatmega328
framework = arduino

[env:test1]
build_src_filter =
	-<alt.cpp>
	+<main.cpp>

[env:test2]
build_src_filter =
	-<main.cpp>
	+<alt.cpp>

The [env] environment, with that specific name, is common to all others in the file, so you get to save a bit on typing! :wink:

HTH

Cheers,
Norm.

Great stuff, thank you normandunbar!

1 Like

Adding additional details in case anybody ever runs into the same situation and needs to keep their files out of lib/ for whatever reason

From the docs build_src_filter — PlatformIO v6.1 documentation

By default, build_src_filter is predefined to +<*> -<.git/> -<.svn/>

It looks like using the build_src_filter param overrides the entirety of the initial values.

To keep the files in include/ and src/ in the context of the example I posted, you would need to do this:

[env:test1]
build_src_filter =
  +<*>
  -<alt.cpp>

[env:test2]
build_src_filter =
  +<*>
  -<main.cpp>

Plus any additional ignores you require (like .git/ and .svn/ as listed in the default setting). Hope that helps somebody someday!

1 Like

Thanks. That helps explain why your class files were never built when they were located in src.

Cheers,
Norm.

1 Like