One platformio.ini for multiple projects

So lets say I have a repository. And this repository contains multiple platformio projects inside of it which share modules (ie. files) common to all projects. For example, projectA and projectB both use a common Button module, so I will nest that Button module in the root folder and require it from there within each projects main.c or whatever.

Something like this.


How would I structure my platformio.ini file? I believe I would need multiple builds - one build for each project, but I am extremely confused with how to do that. My PATH knowledge is very limited.

1 Like

IMO, the best way is to organize common modules (e.g. Button) as separate libraries and then let the LDF find them automatically.

Sure, sounds like something I am trying to do. Do you have an example I could look at?

You just need to specify path to your libraries using the lib_extra_dirs option in your platformio.ini


Is there any way to have the same functionality for include directories?
I need to create a multi-target abstraction, where each target has its own include files and own libraries.

For me it is rather one project with multiple targets.

Also the lib_ignore part for me sadly doesn’t work, as I put target specific source files in a library directory, without doing anything that identifies it as a library.
Some kind of lib_ignore_dir to ignore the whole library folder and add a target specific library/directory with a command like lib_add_dir would be nice.

What I find weird is that when I for example create a new directory that I call target, that is supposed to be used like the lib directory, but in a way that not all of the libraries are added automatically.

I want to use the directory in a way, that I declare for every target a library directory, that should
be built and linked to the binary file.

platform = nxplpc
board = lpc1768

; Needs to stay for every probe
build_flags = -D MCB1700, -D LPC1768, -Wl,-T"./scripts/target/LPC1768/LPC1768.ld", -D DEBUG
extra_scripts = scripts/target/LPC1768/

; ignore everythin in lib folder and only add the platform specific library
lib_extra_dirs = target/LPC1768

;J-Link Probe
upload_protocol = jlink-jtag
debug_tool = jlink

platform = atmelavr
board = atmega328p

; atmega328p specific binary files, e.g. board init etc.
lib_extra_dirs = target/ATmega328p

; build and debugging flags
build_flags = -D ATMEGA328P, -D DEBUG

; upload port.
upload_port = /dev/cu.SLAB_USBtoUART

The behavior of the lib_extra_dirs seems to be different from the lib directory, as header files seem not to be found properly.

this is the current repository’s revision, that I want to get working properly.

Thanks for your time and effort.

Please provide a minimal example project that reproduces the problem to Issues · platformio/platformio-core · GitHub, this is very interesting

Again there is the way through an extra script, the documentation describes a library which includes different source and include folders depending on the target, while excluding source foldes not meant for the target. In the example it’s done by looking at the value of a compile-time flag and adding to CPPPATH and modifying SRC_FILTER.

1 Like

the linked repository revision is the example.
Firstly I tried adding those two libraries, that are currently in the target directory into the lib directory.
In the lib directory, the wrong files are being linked, as lib_ignore lib combined with lib_extra_dirs = lib/ATmega328p sadly doesn’t do the job, because no library identification there.

And at the current revision, the header files in the specific extra directories lib_extra_dirs = target/ATmega328p and in lib_extra_dirs = target/LPC1768 are not being recognized by neither the compiler/linker nor by the IntelliSense, when I try to build it at the current revision.

Edit: opened an issue in the core project.

Well, I literals wrote lib_ignore libwhich was supposed to ignore the whole lib folder contents, but doesn’t as the actual lib folder is not a library, as mentioned above by the approved answer, thus the full library folder was not ignored(just an attempt at stuff that is not supposed to work that way at all).

You can also try src_filter setting instead, which will include different source files for each environment corresponding to different projects.

1 Like

I think the src_filter is the way to go without writing actual python scripts for extending the behavior.

It would be pretty awesome if there was some kind of inheritance syntax/mechanism, in order to have your default [env] contain your basic src_filter stuff

src_filter =

and derived environments [env:lpc1768] just adding stuff to the filter.


src_filter += +<target/LPC1768>

As ini files don’t seem to support the +=syntax, one could differentiate between an explicitly declared global [env] with a explicitly declared src_filter versus the default hidden global environment, where an explicitly declared [env] without an explicitly declared src_filter is considered as the not existing default value.

Where the default one would cause src_filter = +<xyz> to actually replace the whole src_filter and an explicitly declared

src_filter = +<xyz>

would cause the derived environments to actually append to the src_filter


I find it rather weird, that when I use this src_filter and some header files contain
includes with the pointy brackets, that the gpio.h is not being found with #include <gpio.h>, but is found with #include "gpio.h". Including header and gpio.h are in the same directory.

But #include <> is an instruction of ‘look in the standard include paths’ and ‘#include “”’’ is an instruction to look in the relative path specified, then fall back to the standard include paths, no?

And yes, being able to add to environments would be nice… which is why you can do it… :stuck_out_tongue: Have a look at the [common] environment block used in this post, and see how the src_filter is manipulated between environments from a single common one.

1 Like

That’ts pretty awesome :D.

1 Like

Yeah, I thought it was pretty neat that I could start reducing the length of my platformio.ini when the ability to have sub environments inherit from env for stuff that merely duplicates… then Ivan pointed out I could also stack the configuration values … like… cooolll! :smiley:

@scottc11 How did this work out for you? Can you share what worked for you?

to be honest, I think this thread got a touch off-track ahah. I essentially was looking for a way to house a monorepo with platformio. I am very novice when it comes to the compilation process of C/C++ programs.

However, I think the initial solution @valeros suggested about using lib_extra_dirs might work for now until I learn a bit more about make files or something. With this approach I will create a git repo to house all my common modules/libraries and just make sure to put it in an easily found directory for other projects. :man_shrugging:

Still would be nice to see a platformio monorepo example in the docs somewhere! :ok_hand::wink:

1 Like


I struggle also on this question and will try to give different “solutions” (none of them are perfect). The question is: “One platformio.ini for multiple projects” . One may consider that “projects” here is the actual projects you create in platformio. Let’s enlarge the “project” concept to something more general. You want to have different projects/scripts that maybe unrelated but sharing the same library to explore different modules, different way to realize your goal with your microcontroller. In the past, we did “Led_Blink_1.ino” and then if we have a new “project”: maybe the Led will blink each five seconds, we create un new file: Led_Blink_5_Sec.ino" etc…

But now, since we normally all know that we should avoid global library in platformio, that means that each time, we create a new “project”, we need choosing the name of the project, the board, then install all the libraries locally in the libdeps folder, then one may want to add a git repository, sync with github, put this new project in a VS code workspace etc… all those actions take actually a long time compare to the time where we just created Led_Blink_2.ino and upload it: right?

And it’s why tonight, as a newbie, i passed two hours on the forums to find a solution because I’m lazy and it’s definitively a too long workflow to test and upload quickly my “Led_Blink_2.ino”. So I will propose three different solutions. One is correct, the two others may be considered as ugly but there are faster.

Solution 1:

as mention a lot of time: one should go with “lib_extra_dirs” . The author of the question asks for an example. And I was also looking for an example. And I didn’t find an example because it’s quite easy. You create your new project but you don’t add manually each time each library by using the library manager. You simply add this line in the plaformio.ini:

lib_extra_dirs = F:\Documents\PlatformIO\Projects\Previous_Projects.pio\libdeps\esp32dev

Here it’s an absolute path to a previous project where I had already installed each library with the library manager. And it’s works well even if it’s not very beautiful. Alternatively, one may just copy the content of the folder that appears for me like this:

[Sorry, i can only put one image because it’s my first post, thus i removed this one]

And paste it in a new folder. For instance, C:\My_ESP32_Library
then just change the path in the platformio.ini for:

lib_extra_dirs = C:\My_ESP32_Library

And it works. you don’ have to install again and again all the libraries for the new “Led_Blink_24.ino”. It works but it’s still quite slow: you still need to create a git repository etc…

it’s why I propose the solution number 2 (quite ugly): the way I was actually working before trying to find a better way.

Solution 2

I just create a new git branch for each “new project” : thus I have maybe more than 15 branches in the same repository. Sometimes those branches are quite related to each other, sometimes, it’s just a branch to quickly test a new sensor/module before incorporating it to the current main project. Thus no need to create a new project, adapt the path in the platformio.ini, change the baudrate etc… But normally, git branch are not supposed to represent different projects. And later, it may be harder to find quickly a good script if it’s hidden in a git branch.

[Sorry, i can only put one image because it’s my first post, thus i removed this one]

Solution 3

Here is the last solution: the solution that I just found. I keep solution 1 but add somethings else. Thus I create a new project, I change the path to the directory containing already all the libraries to avoid installing them each time, and when I need “Blink_LED_48.cpp”, I don’t do that again, I just actually create a new file!! “Blink_led_48.cpp”!! and I cut and paste the previous “main.cpp” in a folder specially created for that, that I called Previous scripts (watch this folder in the image below). What is important is that it should have only one file with the setup() and loop() function in the src folder to avoid compilation error. This file doesn’t not need to be called “main.cpp”, it looks like one may rename it as he want. Thus, I can make a lot of tests with a lot of files that go to the previous script folder when I need to test a new one. And if I want to take it back again, i just exchange their place. All the scripts are under source control and nothing prevent me to create a new git branch if a change is clearly related to the main project.

Hope those ugly solutions helps. Maybe one of you have even a quicker way to proceed?