JUCE version managementing

Hi I have a simple question perhaps it has been answered before.
In order to develop JUCE plugins it seems necessary to download JUCE and the projucer and then to target the path to JUCE and build your plugin. Then a year later you have old plugins targeting an old version of JUCE. Everything may now be broken as the systems you target are moving so you need to use a newer version of JUCE. How do people manage this problem? Like git checkout an old version to work on old code ? Then checkout a new version and try something new? Let’s say I want to build something from scratch now what should I do ? I know this is kind of a sogtware development 101 kind of question not really a JUCE question. Just wondering how people manage this ? My last project I ended up using cmakelists.txt files to target an LV2 build. Someone pointed my in the direction of pamplejuce which looked interesting but perhaps a lot of overhead. Sorry just ranting nothing specific but I would interested to see how people manage older projects. I mostly develop on an M2 mac. Changing JUCE versions requires reconfiguring XCODE etc. If anyone has any widsom here it might be useful to me thanks Sean

Like this documentation just says “download JUCE”

"Getting started

Download JUCE. Unpack the JUCE folder and place it to some location on your computer. Your user home folder is a convenient place.

Go into the JUCE folder you just installed. Launch the Projucer, which is located there."

Is that what people normally do ? They don’t clone the repo ?

It is much easier to manage versions if you use a proper build system like CMake instead of the Projucer. With CMake, your project script can specify an exact juce version, meaning that the project simply wouldn’t generate properly if the correct juce version couldn’t be found (or you can also have cmake simply download the correct version of juce from GitHub).

2 Likes

thanks Ben then how do you debug your code without XCODE ?

I use xcode. cmake can generate xcode projects

aah thanks Ben do you have some “vanilla JUCE” cmake project as a starting point?

I don’t have a public project template. Pamplejuce is a good one, and there’s also this one

1 Like

In general, this problem of “the toolchain expects to find this thing installed in the system, how do I ensure it’s a specific version?” is an interesting question.

When the “thing” in question is a library, I definitely recommend CMake FetchContent as a starting point, which you pin to a git tag, commit, or branch. Then if you want, on top of that you can add a package manager such as Conan or vcpkg (but tbh most projects are fine with just some FetchContent calls). JUCE helps you here by implementing proper CMake package support, keeping their package version number the same as the git tag name, and also being very strict that even the point release number matches the requested version.

In the case of programs/executables (which applies to the original question about versioning of the Projucer), using containers is a good approach to be able to have a reproducible build environment (this works for libraries too, you can install them to the container’s system directories). There’s also ASDF which is a tool that creates directory-specific program “shims”, allowing you to for example always use Clang 19.1 in directory A but Clang 19.0 in directory B. It’s a cool tool but unfortunately no Windows support yet.

If you want to stick with Projucer, you could try one of these approaches for versioning the PJ executable within your build environment, but really my advice is that switching to cmake is definitely worth the learning curve & time investment, it makes it easier to do all sorts of software engineering tasks, such as building tests, docs, packaging, etc. I’ve even got some cmake custom targets that compile papers using Latex.

2 Likes

Actually JUCE is already version controlled as it’s a git repository.

Ideally you can:

  • as suggested use CMake. Keep in mind though Android won’t use CMake as the primary build system.
  • Make your own project a git and make JUCE a submodule. This won’t stop building if you change anything but you can check the git status.
1 Like

submodule.
If you need to make changes to the juce codebase you can make forks and manage the merging of later juce updates as they arrive.

1 Like

I also think that’s the simplest and most effective. I fork JUCE in a separate repository, make it stable for my needs, sometimes tweak a thing or two and add it as a submodule to the plugin projects. This would allow me to build those projects even if the JUCE repository stopped being available for whatever reason.

I personally find all the CMake scripting stuff an unnecessary hassle and an extra thing to maintain.

2 Likes
git submodule add git@github.com:juce-framework/JUCE.git juce

We do that in each projects git repo. It adds the latest version of JUCE as a subfolder of your project but without duplicating JUCE and keeps the link back to the JUCE github so you can update/pick a specific version.

Git submodules are a bit of a headscratcher when you first use them. But it guarantees you’ll get the version you want when you pull and build your poject.

Maybe CMake FetchContent is easier? But we’ve always done it with git submodule.

2 Likes

Fetch content is useful when you have a small team and don’t want to have to teach your colleagues how to use git - but otherwise, it adds a lot to compile times in a CI pipeline.

Git submodule is usually better, as long as you remember to maintain the submodules for your project (“git submodule update —init —recursive” after cloning the main repo..) - but it can also be frustrating to have so many JUCE copies all over your filesystem, if you’re not careful, or if you work on multiple projects.

Having a ‘one JUCE directory for everything’ approach can work - but here again, you must be diligent about maintaining the link when working on different projects, and it can get in the way when you want to try a different JUCE version for things (I am staying on 7.0.12 for now, but enjoy catching up with -develop when there’s news of new things being pushed upstream).

In general, it pays to work on your CMake and git competency when working on a JUCE project .. I was not really much of a fan of CMake-based projects for a few years, but after some time spent in JUCE development I’ve come to appreciate it a lot more.. and I’ve now become much more enamoured with it as a solution for many things.

But you do need to invest time to learn these tools and the methods that will keep things hygienic - without some strong tooling/methodology policies, you can mess things up immensely.

There is light at the end of the tunnel: CMake and competent git habits are very useful when the time comes to do continuous integration/automated builds/packaging/signing/notarization. There is something very satisfying about pushing to a branch, waiting a few minutes, and having a fully-functioning distributable .zip or .exe spit out at the end of the pipeline, somewhere. Good CMake and git habits will get you to that point, rapidly


1 Like

Why would git submodule have better build times than FetchContent?

If you have quite simple plugin projects (that can be professional, commercial products), CMake is overkill.

If you want to learn and use it, please do, but for simple projects you really do not need it.

The Projucer can generate your Visual Studio solution file and Xcode project file, and can be used as a command-line tool in a CI/CD environment.

2 Likes

I agree about CMAKE. For really large complex projects it can be actually incredibly tricky to convert from Projucer to CMAKE. Remember Matchbox Ben?

Re: submodules, we literally have a separate copy of juce for every project, maintained as a submodule in each project repo. We absolutely need to know that build 123 of my product X uses version 345 of juce. I can switch back to any earlier commit in my repo and know I have exactly the original version of juce.

A single system wide copy of JUCE is crazy.

2 Likes

You’re right that cmake can get difficult/complex with larger projects, typically the greatest difficulty happens when trying to integrate large, complex dependencies that do not themselves support cmake (ffmpeg is a good example). It’s possible but basically requires doing custom scripting to call the project’s configure & makefile steps, which might be different on each OS, etc. This complexity also exists in the non-cmake case too, though, you must have some custom scripts that are building your dependencies.

But as far as just simply using juce and getting reliably the correct juce version, that’s quite easy. If you write a FetchContent call asking for Juce 7.0.9 (for example), then cmake will first check if that exact version happens to be present in system dirs, and if not then will git clone it at configure time. You can also configure it to always use git and never system packages.

FWIW downloading the zips from the JUCE Releases and unzipping them is much faster than using any method involving git. Cloning with git (directly, or through submoduling) comes with a lot of baggage that you probably don’t need unless your build system actually needs to do git-related things with JUCE. The JUCE repo is ~264MB while the macOS zip is ~44MB.

E.g. compare the time taken to run these two commands:

$ git clone git@github.com:juce-framework/JUCE.git
...
Receiving objects: 100% (263321/263321), 264.37 MiB | 2.06 MiB/s, done.

$ curl -L -H "Accept: application/octet-stream" -o juce.zip https://api.github.com/repos/juce-framework/JUCE/releases/assets/219387682
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
...
100 44.2M  100 44.2M    0     0  1888k      0  0:00:23  0:00:23 --:--:-- 2035k

If you’re on GitHub Actions, or have the GitHub CLI you can also use:

$ gh release download 8.0.6 -p '*-osx.zip'
2 Likes

You could add --depth=1 if you don’t care about the commit history. Though the total time still depends on your web connect quality.

More info: How to make shallow git submodules? - Stack Overflow. I have never tried though.

2 Likes

I don’t agree with the negative statements about CMake. Faffing around with Projucer is a serious time sync, too. If you get your tools set up, CMake is just another source file to maintain, and it is very easy to do so. Plus, changes to CMake are a lot more readable over time/commits to a repo, than changes to a .jucer file. And if you use an IDE such as CLion, you get code completion and CMake module navigation, just like any other source in your project. CMake knowledge extends beyond JUCE, too. There’s a reason its commonly adopted in other projects - its very, very effective.

I am yet to encounter a .jucer file that can’t be rapidly and efficiently converted to CMakeLists.txt with an LLM. Every single .jucer file I’ve found in the awesome-JUCE list, for example, has been easily converted to a functioning CMakeLists.txt file with an LLM in seconds. That trouble is so over, folks.

Using FetchContent can impact build times in CI because it gets triggered with every build - whereas having a git submodule config means JUCE is outside the build-tree. Having JUCE as a submodule in your project is preferable because you can more directly control the JUCE version you’re building with, and when you push to your repo, this version is part of your repo forever.

In this day and age, if you’re not using git effectively, you’re just making excuses not to adopt a good methodology. I get it, its just another thing to learn, but taking the time to learn good tooling and methodology is an easy investment for any development, pro or otherwise, to make.

Projucer has its place - but for newcomers to software development though, it can actually be more of a burden to dive into .jucer terminology than just learning CMake. The cyclomatic complexity of a project is increased by the Projucer scaffolding - it is reduced with CMake. That can impact developer productivity in both directions - CMake is more future-proof and versatile. Want to include a git hash in your projects version string that identifies the very commit of your release? Really easy with CMake. Not so easy with Projucer.

But either way, for anyone reading this thread and working out which to invest time in, both tools essentially do the same thing. You just get more hand-holding with Projucer, and that can be important if you’re just starting out.

Eventually though, converting to CMake is very easy, and effective when you get to the point of doing CI-based builds and automated releases.

It’s quite interesting to observe the diversity of opinions though. Mine is just one opinion in the stream 
 but I will never agree that downloading .zip files is superior to git, in any way whatsoever. :stuck_out_tongue:

4 Likes