JUCE structure simplification ideas


#1

Recently I’ve been thinking about how I could simplify the library’s structure a bit, with two aims in mind:

  1. To cut down all the multitude of static/inline/amalgamated etc ways that you can link to juce
  2. To make it easier to use just the bits that you need, and avoid the overhead of pulling the entire library in if you only want to use a few classes.

So, I’d be keen to hear people’s views, but what I’m considering would be something along the following lines:

  • ditch the static library versions altogether. (And any remnants of the DLL builds). Ok, I know some people have been statically linking to it, but you could still create your own side-project that put it inside a static or dynamic library if you really need to, that’d be easy to do. I can’t actually think of any advantages whatsoever in statically linking - normally it’s used because it’s easier than including all the hundreds of source files in each project that uses them, but since juce fits into a single source-file, adding it to a project is trivial, and the extra layer of using a library and setting up the library paths, having different binaries on each platform, with different compile settings, etc just outweighs any advantages. If you have a killer use-case for static linking, I’d be keen to hear about it.
  • ditch the amalgamated files and instead simply provide a juce.cpp (and juce.mm) file alongside the juce.h header. So to use it, you include juce.h in your code, and add juce.cpp to your project. Job done. No further instructions required.
  • for building just parts of the library, there’d also be a range of other headers: probably things like juce_threads.h juce_audio_devices.h, juce_components.h, etc. So rather than including the full juce.h, you could just include the bits you need. Obviously some of these sections would be dependant on other ones, but it’d be a way to let you just pull in the minimum possible for what you’re doing.
  • Internally, there’d be a bunch of macros like JUCE_BUILD_COMPONENTS, JUCE_BUILD_AUDIOFORMATS, etc, to control the bits that get included, so you could also include juce.h after having set up some flags to indicate which bits you want to use, and that’d have the same effect as including the different header files.

Thoughts? Criticisms?


#2

No criticism, just an explanation of how my Visual Studio 2008 project is structured.

I use my own project file for juce, instead of the one that comes with juce. It builds a statically linked library. The outputs are set up in a way to use environment variables, and send the intermediates and final product to a location outside the svn source tree:

Here you can see Output Directory and Intermediate Directory settings, they are the same for all targets. “OUTROOT” is an environment variable that I set in the IDE.

[attachment=1]1.png[/attachment]

My .exe is built from several sub-projects that produce static libs (including Juce). They all make heavy use of property sheets for shared settings.

Every project inherits “Common” property sheet, there are also “Release” and “Debug” property sheets. So if I change a Release setting, it is inherited by all projects automatically. Each project also gets its own project-specific property sheet, these settings are applied to all targets (Release and Debug). You can see these property sheets here:

[attachment=0]2.png[/attachment]

The benefits are common settings for all libraries. The disadvantage is that when files are added or removed in the juce source tree, I must manually apply those changes. I always inspect the Git changelog for new. deleted, or moved files. Sometimes things slip through (I never noticed that juce_MidiInput.h was moved for example).


#3

So in fact it’d be easier if I went for the option I’m describing above, because your static lib project would just contain juce.cpp, and you wouldn’t have to worry about keeping track of internal changes? (And in fact you could do the same thing now by just building juce_amalgamated_template.cpp)


#4

So in fact it’d be easier if I went for the option I’m describing above, because your static lib project would just contain juce.cpp, and you wouldn’t have to worry about keeping track of internal changes? (And in fact you could do the same thing now by just building juce_amalgamated_template.cpp)[/quote]

How would stepping in the debugger work? Visual Studio 2008 stops debugging correctly when a source file has more than 65,536 lines. What about making changes or applying patches to Juce?

I like being able to open specific juce headers and look at the interface in a source window while I am working on my code. I wonder if that work-flow would be possible with the new scheme.

Most of the time Intellisense is broken for me and I have to manually open the specific juce header that I want to browse for its api.


#5

I’m not talking about the big amalgamated file, just the template for it, which includes all the other files.


#6

This is not a killer argument, but i like the current workflow with a statically linked juce-project in my VS-Solution. I never use any documentation, i just look into the jucer-sourcecode, the well organized file-structure, and look what it does, also its very easy when it comes to debugging etc, or if you want apply changes to juce for bug-finding. I never liked the amalgamated-one-big-file structure, first intellisense gets mad, and sorry its very messy to work with.


#7

Ok, being able to browse the juce files from within your project is a handy thing. (Although in Xcode I have to do that by having a separate project window open anyway, so it’d really only be helpful in MSVC)

Indeed, and I don’t use it myself any more, which is why I’m thinking of ditching it.


#8

one idea is that the introjucer just adds all juce-relevant files with folder structure to the project, but than you need to use the introjucer for update, but this will overwrite all own-settings in the project files (for example i use the Microsoft MASM as a Custom Build Tool for special files) and overwriting these settings is a no-go.


#9

I for one can live without the amalgamated stuff. Your proposal sounds like a much better idea.

Doesn’t dead code stripping throw out everything that’s not used anyway? Why bother with “partial” builds?


#10

I suppose partial builds potentially reduces build times? … Which is one reason I use static library version for most projects: the build times when moving between many small projects can really add up (especially when trying to keep relatively up-to-date with the Juce tip). I don’t use the static library version for iOS apps or audio plugins (as the benefits are outweighed for me at that point). But as Jules says, it wouldn’t be too difficult to recreate a static lib project. Or perhaps the static lib project could move to /extras as an Introjucer project under the new structure while this is being deprecated?


#11

Yes, that's a good idea.

In fact, it's just occurred to me (doh!) that I actually spend most of my time working in the static lib project! I never (or very rarely) actually *use* it as a static lib, but I always have the Xcode project open when I'm working on the juce classes, and it's where I do all my editing and browsing of them. So in fact I do need to keep it around somewhere!

Yes, that’s a good idea.

In fact, it’s just occurred to me (doh!) that I actually spend most of my time working in the static lib project! I never (or very rarely) actually use it as a static lib, but I always have the Xcode project open when I’m working on the juce classes, and it’s where I do all my editing and browsing of them. So in fact I do need to keep it around somewhere!


#12

No it doesn’t.
Think about it, in a CPP file, any function can refer to any other function inside the same “compilation unit”. The compiler just pust code like “jump 345 bytes from here” code.
Then, at a much later time, the linker actually build a table of all functions used, and put them all in the final binary file. It can’t remove a function since it would imply recompiling the code to fix the jump’s offset.

The only way to remove such function is either : remove all functions in a compilation unit, or put each function in its own section, and then let the linker garbage collect the useless section (but this cost a lot in execution speed since all call to other function have to go through an extra jump in the IAT/jump table + loading time increased because of IAT jump table generation).


#13

I vote for keeping the static lib project.

I’m using Juce is a lot of projects, and I have compiled it once for all as a static lib.
Then using it in all my other projects is simply a one liner in my premake/automake script where I set up the link/include path and that’s all.
I don’t have to wait for all the library to recompile again each project, and whenever I fix a bug in the library, all the other project will be fixed at the next link (which is invisible for the users), I don’t have to remember to regenerate amalgamation and/or move/copy the updated juce.cpp/h around in all my projects.

Since I’m using a lot of libraries in my projects (SQLite, ffmpeg, openssl, etc…) adding Juce as a library is as easy as any other library.


#14

I’m not talking about the big amalgamated file, just the template for it, which includes all the other files.[/quote]

OK for the .h but what about the .cpp ? Isn’t it gonna be a huge source file which includes all the rest ? I must admit I don’t really understand …


#15

Yeah LOL I was wondering about this but I didn’t say anything. Like you, I browse using the source tree in the project file. So removing it doesn’t make a whole lot of sense to me.


#16

I’m another one that does this. My memory isn’t what it used to be so I use the project to filter down to the class I need, plus its useful in those (rare!) occasions I find a JUCE bug, or want clarity on the source code implementation to quickly see the .cpp file.


#17

I also use the static lib project that, and I can’t even contemplate how painful it would be to try a change in Juce without it. I also find that xcode (on my machine) completely hogs the machine for 5-10 minutes when doing the whole juce library inline with the project, and that happens every time I do a clean. I’ve gradually moved back to using the static library more recently - it takes my build times way, way down, and makes debugging, looking at juce code, etc easier.

Meanwhile - on the piecemeal topic, yeah awesome. That would be nice with targets - in xcode, at least.

Bruce


#18

Agreed. I’m using XCode4 at the moment and I find I need to clean fairly often as sometimes the the app will just fail to launch until I clean and rebuild.


#19

What comes to my mind now is that I very often need to set breakpoints in the Juce library for debugging, e.g. to answer questions like “who the heck does delete this object?”, or to temporarily hack one or two lines in the code for experimental testing.

This is extremely cumbersome with the amalgamated files. I would very much like to be able to include all the files individually, so I can more easily debug and experiment.

I don’t care much about compile time, because I have a capable enough development machine. A clean build of the “Juce” project goes through in 30 seconds, so why bother?


#20

I’m not sure I clearly understand the difference between this solution, and the amalgamated version of the library. Could someone please shed some light on this ? :slight_smile: