Can I have multiple top-level .INO files in a Workbench project, and if so, how do I target one or the other for build?

I just started really digging into Workbench on VScode. It’s pretty great.

However, I am having trouble just getting what I would consider to be basic info about how this IDE works.

My first question: I have a project that requires a master Argon and a slave argon. They run different firmware. I would like to have one project with the two INO files, and then target one or the other for build/compile/flash at a time. I can’t figure out how to do this.

Secondarily, is there a good place to learn how this environment works? What and where are these config files? If I remove a library, what do I need to edit? Are there additional options for the IDE and the build process? Where might I learn all this?

I have tried following the VScode tutorials, but seriously… “Here’s how to install themes!” is nice to know, but WTF where is the important stuff!!!

I just started really digging into Workbench on VScode. It’s pretty great.

awesome! happy to hear :pray:

I have a project that requires a master Argon and a slave argon. They run different firmware.

VSCode has a featured called “multiroot workspaces” that seem to align pretty well with what you are trying to do. read up on them here:

is there a good place to learn how this environment works?

if you haven’t already seen them, we have a bunch of docs and walk-thru videos:

in particular, you might want to check out:

Getting Started with Particle Workbench:

Building Firmware Locally with Particle Workbench:


  • cmd/ctrl+shift+p reveals VSCode’s “Command Palette”, typing Particle: filters the list of available commands to just those added by Workbench / Particle
  • projects need to be formatted specifically to take advantage of Workbench functionality - run Particle: Create Project, follow the prompts, and check out the results
  • under the hood Particle Workbench uses the Particle CLI to do many of the core operations - login, cloud compile & flash, project creation, etc. you’ll see this in effect running commands like Particle: Serial Monitor
  • basic project & library settings are stored in, VSCode / Workbench-specific settings in .vscode/settings.json
  • you can interact with the Local Compiler directly (inspect current settings, apply overrides, view and run available tasks) - run the Particle: Launch Compiler Shell command and play around
  • help us help you by providing as much of the following when reporting issues, etc: How to report bugs and provide feedback (Workbench), How to report bugs & provide feedback (CLI)

hope it helps :+1:

1 Like

Thank you for all that. But I’m not sure it answers my questions.

For example, I can’t seem to have two .INO files in the same folder. So it seems that either VSCode or PW is configured to search for and find a top level .ino/cpp file and compile that.

I tried to use the CLI and specify the top level file, but that failed, with or without the 2nd .INO file.

So one kind of thing I’d like to know is how does this tool (presumably PW but maybe just VSCode?) know to use the .ino file as the top level? And is there an easy way to target a specific one or switch?

The Multi-root workspaces thing you sent doesn’t really seem to help me. What I want is to be able to work on two .ino files that share both installed libraries AND possibly other included .cpp files with shared code, but ones not managed like libraries. For example, I have some data structures defined in those files. I’d like to be able to have one copy of those data structures, manage it in place, and not have to worry that my two executables are compiled with different versions. The Multi-root feature seems to be a way of working on two separate code bases at the same time, but this isn’t really a separate code base.

All that said, I appreciate your help, but if your answer is “Look, it’s really a lot easier if you just maintain two separate folders/projects for both the master and slave”, I will trust you. :slight_smile:

That is not possible.

And it’s not the “top level” (whatever you are refering to here) but the one and only .ino file that resides inside the src folder next to the file of the project.

What I’d do would be one single .ino file which may pull in either the master or slave code (stored in their respective .cpp files) via compiler directives.


That is good to know!!!

Seems reasonable. Thank you!

1 Like

There’s no requirement to have an ino file. I’d just set it up with all cpp files and set up your Makefile to build what you want.

And I just copy libraries to the project directory too. particle library copy NAME.

Yup. I haven’t worked with makefiles before. I’ll look into that.

But I assume that if I create a makefile that VScode/PW will recognize that and use it for the compile automatically?

Sorry, I haven’t used vscode much, but even vscode shouldn’t need there to be an .ino file. I don’t have any ino files in any of my projects.

Looks like, on closer inspection, that VSCode doesn’t use a makefile without an extension to set it up.

I think I’ll try and stick with the VSCode standard for now, but thank you.

No worries. Even with standard VSCode you should still be able to build things without any .ino files.

See: . I just tested it and it worked fine for me.

1 Like

@ScruffR, can you just let me know if this is some type of standard with VScode, or something to do with the PW extension? I looked in the project setup and configuration files, and there’s nothing about INO files. This leads me to believe that the extension has set something up somewhere.

So looking in the project files, I see this in settings.json:

    "extensions.ignoreRecommendations": true,
    "C_Cpp.default.configurationProvider": "particle.particle-vscode-core",
    "cortex-debug.openocdPath": "${command:particle.getDebuggerOpenocdPath}",
    "files.associations": {
        "*.ino": "cpp"
    "particle.targetPlatform": "argon",
    "particle.targetDevice": "DEV_ARGON_1"

So this seems to say…

  1. use the particle-vscode-core extension
  2. treat any .ino files as .cpp files
  3. Holds on to my last set device options (And provides a debug setting, which I haven’t used yet)

So I take it that the extension core is what dictates the plan to search for an INO file, and treat is as the top level? But if that’s the case, why would the extension alias be set here? Or is this redundant or placed here for override/seeding in case a user wants to have more extensions?

Cool. But I am still trying to understand what part of the compile tools recognizes which file has the main entry point for the program.

In one of my earlier issues, I had to change the extension for an example buried in a library because they used .ino, and the compiler was confused, seeing multiple setup() and loop() definitions. So it appears that the Particle Extension looks for an INO and includes it by default.

If I were to change the extension to cpp on my top level file, how would the compiler know where to start?

(Just tried to invoke Particle: Cloud Compile, and… failed to compile)

So yeah, looks like the Particle Workbench assumes the project has one and only one .INO file (or if there are more, they can’t contain duplicate function definitions).

Interesting question. I think it’s the one that includes #include "Particle.h. And you just need one setup() and loop() in there. When you rename from .ino to .cpp you have to add that include.

I renamed my source to rrr.cpp and it compiled just fine provided I added the import.

Are you using Particle Workbench in VSCode? None of my files have #include Particle.h.

I think that when I first tried these out with a Spark Core I used that in the online IDE.

(I tend to move on to something else and then come back to these guys every few years to solve another problem! So I start over from scratch essentially. I think you could drop that include statement with the Photons a while ago, if you were using their tools.)

I’m pretty sure that’s not the case but I’d have to test.
The “main” file of the project is the one inside src that holds setup() and/or loop() and there can only be one that holds either one of them.
BTW, it’s not an issue for the compiler if there were more but the linke wouldn’t know which one to pick. When putting everything together all global symbols must be named disambigously.

The thing with .ino files is that they undergo an extra preprocessor run to convert them into .cpp files by adding some things like the #include statement @kenmacd mentioned as well as adding function prototypes where needed.

But they should when they are using any Particle symbol. For .ino files the preprocessor will add it when it’s not present, for .cpp files you must add it.


Alright! This is the good stuff. Makes me feel more assured about what’s happening.

Is this all laid out anywhere specifically? Or is it kinda buried piecemeal within all the reference?

For me this is tribal knowledge, but it may well be documented somewhere - I just wouldn’t know where :wink: