[CMake] Joining multiple directories into one

Brad King brad.king at kitware.com
Mon Mar 9 10:03:40 EDT 2009


Jussi Pakkanen wrote:
> Hi all
> 
> I'm looking into compiling OpenOffice.org with CMake. Currently it
> uses dmake and a custom build tool. The basic structure is that every
> logical component (Writer, widget toolkit etc) has its own
> subdirectory. These are well separated.
> 
> The problem comes from the internal structure of these components. The
> most common case is that the component produces one product (usually a
> shared library) from source files scattered in several different
> subdirectories. As an example:
> 
> dir1/foo.cxx
> dir1/foo2.cxx
> dir1/subdir/baz.cxx
> dir2/sub1/ggg.cxx
> dir2/sub2/rrr.cxx
> 
> And so on and so on. Each subdirectory has a dmakefile that lists the
> source files to use. I have written a parser that converts these to
> CMake's syntax. Every component has a subdirectory called "util". This
> is where the final product is defined and built. What I want to know
> is what is the correct cross-platform way to do this in CMake. Here
> are some choices I came up with so far:

The easiest way is to put the add_library() call at the top-most directory
which shares all the sources and use relative paths to list them

   add_library(mylib SHARED dir1/foo.cxx dir1/foo2.cxx ...)

> 1) Build every subdir to a static library and link them to the final
> shared library. I think this fails, because the files do not get all
> the proper -FPIC switches and so on.
> 
> 2) Build every subdir as a shared library and join them to the final
> lib. I tried this ages ago and turned out merging shared libraries
> (also static ones) was not possible. Probably still the case.

I recommend against these two.

> 3) Write source files to a variable and then add_library(foo SHARED
> ${SOURCE_FILES}). But what should I write in SOURCE_FILES? Should it
> be "foo.cxx", "dir1/foo.cxx", or perhaps even "../dir1/foo.cxx" (since
> add_library is done in the util subdirectory)? Also, do I need to set
> the variable to cache, since changes in subdirectories must be visible
> in their parent and siblings? Preferably the variable should not be
> visible in other components.

This is the same as the solution I suggest above but moves the add_library
call into a subdirectory.  If you use it, you can either list the sources
by full path or by relative path from the CMakeLists.txt file containing
the add_library call.  It is much simpler to put the call at the top-most
location though.  CMake's makefile generator will still hide all the
object files out of sight.

> Sounds easy so far? Well, there is still one more thing. Every source
> file may be tagged with a special value, and those files must be
> compiled with special compiler switches (dealing with exceptions).

By "compiler switches" do you mean real compiler flags or just preprocessor
symbol definitions?  The COMPILE_DEFINITIONS property is only for
preprocessor symbols.

> If a file is not tagged, different compiler switches must be used. I can
> set COMPILE_DEFINITIONS easily, but can I make it drop existing
> switches? I can code logic to the converter script that calculates the
> the set difference between all source files and tagged ones. Then I
> can set COMPILE_DEFINITIONS for each of these separately, but I'd
> rather not if there is an easier way. :-)

This is probably the best way.  If one were writing CMakeLists.txt files
by hand from scratch, this is how it should be done.  However, I suggest
not making excessive use of per-source build properties because they
do not perform very well in the VS IDE (this is not CMake, but the VS
IDE implementation).  The definitions will work, but they cause the IDE
to use a separate invocation of the compiler for every source file
instead of sharing one invocation for many sources in a target, which
leads to slower builds.

Can you provide more detail about the purpose of these switches?  Why
does every source file need one?

Thanks,
-Brad


More information about the CMake mailing list