SOUL install location and long #include statements

Hi there.

I’ve created a PKGBUILD script so that I can more easily install the latest release of the SOUL headers and shared library on my Arch Linux machine, which got me thinking about where the idiomatic Linux-feeling place to put these things would be.

For the shared library it is obvious to put it at /usr/lib/libSOUL_PatchLoader.so, but the header files are less obvious…

My first thought was to pull the header files out of their API folders and put them all together in /usr/lib/soul/ or /usr/lib/SOUL so that I could include things like #include <soul/soul_patch.h>. It would be even nicer if the files were named more tersely so that I could write #include <soul/patch.h>. Unfortunately, it looks like because of the way the header files refer to each other, a lot of the directory structure in the repository has to be maintained in order for e.g. headers with helper classes to find the main headers they use, or for main header files in the API to find the 3rd party dependencies from choc.

I settled on moving the whole API and 3rdParty directories into /usr/lib/soul/, so to include soul_patch.h I write #include <soul/API/soul_patch/API/soul_patch.h. That’s a bit of a mouthful, but it works I guess.

Looking at the example code and some of the other projects I’ve seen, it seems expected that the headers should just be sitting somewhere nearby your project so that you can include them using a path relative to the source code. This seems damaging to the ecosystem; if I want to work on someone else’s cool open source SOUL project, I have to either patch every location that includes a SOUL header to look for them in the place where I happened to install them on my system, or switch my installation method to conform to the other project, or maybe set up some symbolic links so that the other project can still find things via links to their location on my setup…

Maybe it would be a good idea for there to be an agreed upon, canonical, expected location for at least the header files, so that everyone can just write the same #include statements and expect it to work.

And if such a convention were to be instituted, maybe it would also be a good time to rework the directories a bit so that we can all write more concise #include statements (<soul/patch> vs <soul/API/soul_patch/API/soul_patch.h>) while we’re at it. This could even be done without changing the existing directory structure by adding dummy headers in /source (or wherever the includeable API ends up living permanently) that just #include the relevant files.

I imagine it might look something like this (at least on *nix systems):

/usr/lib/soul/patch           // dummy file includes API/soul_patch/API/soul_patch.h
/usr/lib/soul/venue           // dummy file includes API/soul_venue/API/soul_venue.h
/usr/lib/soul/future_api      // dummy file includes API/soul_future_api/API/soul_future_api.h
/usr/lib/soul/API/...         // existing API folder
/usr/lib/soul/3rdParty/...    // existing 3rdParty folder

Then we could have concise include statements while still allowing header files in the API to reference each other relative to their position in whatever arbitrary directory structure they live in.

What have other people been doing when installing SOUL for development? Is anyone else… dissatisfied… with the current include statements? Also, how would this look in a Windows environment ideally?

I guess you guys on the development team are swamped with other much more important things, but have you given this any thought? Is the way we include soul APIs likely to change in the future, or is the current status the expected method for all time?

Edit: Typos.

Our main design goal with soul is to pick the design of “least surprise” to users so I’m really happy to discuss this and make some changes if we can make it closer to what most people expect.

But I do find it a bit of a strange question, as I’m really failing to understand why it’d make sense to ever put the soul headers in a global location in the first place!

We obviously have a bunch of in-house test projects which include SOUL, and I also use it in real-life in the Tracktion Waveform repo, but in all these places, we just add the SOUL git repo as a sub-repository. That way, there’s zero installation required to set up a machine (or more importantly a build server) correctly, no paths to set, no version syncing problems, and there’s nothing platform-specific needed for Windows or other non-unix targets.

But maybe I’m thinking too much like a ‘pro’, and clearly there will be people who just want to slap the latest soul version “somewhere” on their machine and then hack away at random test files that don’t live in a repository, without any thought about how well they’d work in a multi-platform team project, and we probably need to make sure it’s good for both!

BTW I should mention that I’m in the middle of redesigning the whole performer/venue API so you can expect a lot of refactoring in the header structure anyway.

Perhaps the top-level structure of the repo should be something like

soul/
  docs/
  examples/
  tools/
  include/
    patch/
    API/
    3rdParty/
  source/
    modules/

So you might include them as

#include <soul/include/patch/patch.h>

?

Or… as well as those sub-folders in include for all the different uses, we could have a few top-level headers which would be what you’d actually need, e.g.

soul/
  include/
    patch.h
    patch/
      [contains stuff that a user isn't expected to include directly..]
    venue.h
    venue/
       [likewise]

and then if you’re doing a patch you’d just do

#include <soul/include/patch.h>
1 Like

Yeah, what you describe sounds pretty spot on, except instead of having an include folder, I would suggest having a soul folder with all of the include files. That way, for those like me who just want to slap the headers somewhere on the system, we could copy the soul folder into /usr/include and then write #include <soul/patch.h>.

This would also make it possible, in an environment where the whole SOUL repo is a sub-repository (sub-module or sub-tree?), to write the exact same include statement if you pass a flag to the compiler to search the SOUL repository for header files, like -I/path/to/SOUL. That seems nice to me–everyone can write the same include statements that way.

Unless, is there some advantage to having include statements with relative paths like #include "../SOUL/soul/patch.h"? I guess it saves you from having to have a build flag; maybe the benefit of that increases in a larger multi-platform team project?

In any case, the refactoring of the directory structure you described in your last post would be a major improvement from my perspective, regardless of where your SOUL headers live. I especially like the idea of having top-level headers for the most commonly included interfaces. One more thing to enthusiastically look forward to in a future release coming soon!