[CMake] Controlling the locations of files produced by Visual Studio

David.Karr at L-3COM.COM David.Karr at L-3COM.COM
Wed Nov 26 16:54:33 EST 2008


The context of this question is that I'm porting an existing project
from Visual Studio 6.0 to Visual Studio 2008.  This project has used
CMake for several years, but before that it already had its own file
structure into which it put all the files that it built.  

Specifically, each Visual Studio project had its own subdirectory within
the overall project, like this:

  ${my_project_SOURCE_DIR}/project1
  ${my_project_SOURCE_DIR}/project2

When building the Debug configuration (for example), most of the output
files (including OBJ, IDB, and PDB files) went into "Debug"
subdirectories, like so:

  ${my_project_BINARY_DIR}/project1/Debug
  ${my_project_BINARY_DIR}/project2/Debug

But there were several exceptions.  The LIB files were all created in
one directory, while the DLL and EXE files were all created in another
directory:

  ${my_project_BINARY_DIR}/lib  (LIB files)
  ${my_project_BINARY_DIR}/bin  (DLL and EXE files)

This limits us to building only one configuration per build tree, but
that's quite all right with everyone; you want a different
configuration, you set up a new build tree.

Several developers who work on this project every day use the Visual
Studio IDE in out-of-source builds for all their work.  And they have
various useful options, for example a single STRING definition on the
cmake.exe command line controls whether they get browse info files.
I've also set up CMake so that they can add or remove sources from a
project just by creating or deleting files in that project's directory.
Meanwhile, at least once a day, a very intricate Perl script performs an
in-source build of this project, using the command-line Visual Studio
compiler/linker, always building whatever we have set as the "default"
build configuration; it then installs the result within a much larger
system; and this automated process is maintained by an entirely
different set of personnel on a different network.

So I have one set of "clients" who visibly benefit from CMake every day,
and another set who get no perceived benefit from CMake at all and would
prefer that the developers just hand over preconfigured DSW and DSP
files as the developers of other projects in the larger system do.
Moreover, I am really in no position to debug the procedure that
incorporates this project's output into the larger system, so I'm
reluctant to have files written to directories other than the
directories where they've always been written; I simply don't know which
changes might break the system build, and every time our group's use of
CMake causes any problem for anyone else, we are pressured to stop using
it.


For Visual Studio 6.0, I could get all the files to come out exactly
where I wanted; I added command-line options to CMAKE_CXX_FLAGS, for
example "/implib" and "/out", for part of the necessary output paths,
and created a Templates directory in my project containing modified
copies of some of the files from the CMake Templates directory to take
care of the rest.  But the Visual Studio 2008 generator works on a
completely different design that doesn't use templates and that appears
to ignore command-line options such as "/implib" and "/out" (for quite
understandable reasons, since you can no longer just copy these options
into the VS project files).  Instead, there is a rigid scheme governing
certain details of the directory structure.  For example, the files that
used to be in ${my_project_BINARY_DIR}/project1/Debug are now
distributed between two subdirectories:

  ${my_project_BINARY_DIR}/project1/Debug
  ${my_project_BINARY_DIR}/project1/project1.dir/Debug

I _guess_ this _probably_ won't break the automated script, and if not,
I might be able to live with it (in fact sometimes it could be
convenient), but the reason why CMake creates project1.dir simply
doesn't exist for our project; our directory names will always follow
the pattern x/x.dir/Debug, _never_ x/y.dir/Debug, so this feature seems
to be a completely unnecessary risk for us.

Another thing is I've found no way to get CMake to put the LIB and DLL
files into the lib and bin directories.  The closest I can get (in the
Debug configuration) is to have the files written to these directories:

  ${my_project_BINARY_DIR}/lib/Debug  (LIB files)
  ${my_project_BINARY_DIR}/bin/Debug  (DLL and EXE files)

This seems highly likely to get me into trouble.  I can have the files
built into some Debug directory and then copy them to the desired lib
and bin directories in the INSTALL project, but I'm still not 100% sure
I can do this without breaking something in the system build, and even
if it doesn't, someone might complain about the extra copies of the
files.

It would be ever so much easier for me if CMake just provided a couple
of extra options to say where certain output files got written.  For
example, if a SHARED library project were built in the Debug
configuration with the following CMake variables,

  SET(CMAKE_EXPLICIT_OUTPUT_FILE_DIR ${MY_DLL_DIR}) 
  SET(CMAKE_EXPLICIT_IMPORT_LIBRARY_DIR ${MY_LIB_DIR})

this would be equivalent to setting the command-line options
/out="${MY_DLL_DIR}/project1.dll" and
/implib="${MY_LIB_DIR}/project1.lib" for the Visual Studio linker.  (I
suppose it could also cause the Unix makefile to produce
${MY_DLL_DIR}/project1.so and/or ${MY_LIB_DIR}/project1.a when
appropriate.)

I thought perhaps the property IMPORTED_IMPLIB might do some of what I
want, but I haven't figured out how to use it at all.

What I actually have implemented (to assist my port to VS 2008) is a
modification of CMake 2.6.2 that supports something like this:

  SET(EXPLICIT_OUTPUT_FILE_NAME ${MY_SHLIB_DIR}/project1${SHLIB_EXT}) 
  SET(EXPLICIT_IMPORT_LIBRARY_NAME ${MY_LIB_DIR}/project1${LIB_EXT})

In other words, I can hack one or two classes in the CMake source to do
everything I want, and I can probably get away with this, since the
people who run the build script will just use whatever copy of cmake.exe
I hand to them.  But I would prefer to use existing CMake functionality
if it exists; and if it doesn't, I wonder if it would be worth adding
this functionality as an option to CMake.  (My hacked version actually
acts exactly like CMake 2.6.2 if you don't use any of the three or four
new variables I defined.)

David Karr




More information about the CMake mailing list