[CMake] Windows library target names

Brian Davis bitminer at gmail.com
Fri Jul 23 11:23:40 EDT 2010


--snip--
I'm using Boost and I've never hard to work with special defines and
compile flags. That's the power of proper automatic support.
--end snip--

That's the power of Boost.  These guys have really figured it out.  I too
would like to see some of the Boost.Build concepts make their way into
CMake.  I just noticed this thread and I feel it is very important for the
future development of CMake.  So I am going to break this down... preface
all statements with IMO (which I hope accounts for something after 9yrs of
embedded systems development)

-snip-
I've only got a single lib dir. Shouldn't all variants have a unique name?
-end snip-

Yes! Yes! Yes! Boost.Build and boost-cmake do this right.  Though I have had
to patch boost-cmake.  Take look at BoostCore.cmake in boost-cmake this
should lead you in the right direction.  Why is this important?  When you
fall into the development of embedded systems and need to build realease,
profile, debug for multiple targets the name mangling is a critical need to
keep everything strait.  I mean imagine for a minute that you have three
embedded targets of different architectures, 486, 586, and PentiumM and you
need to build your software for each.  Boost-Build also allowed us to build
ALL VARIANTS of ALL TARGETS with 1 command line.  boost-cmake is the closest
attempt at this in CMake which will generate projects for Release and Debug
and show both in the VS project regardless of which variant you are building
for.

-snip-
Shouldn't this be done automatically?
-end snip--

Yes! Absolutely!  CMake Should!

-snip-
No way. Not all users would want that on all platforms that CMake
supports. Also it is very easy to add a single line to your
CMakeLists.txt file..
-end snip-

Then provided it for those who do and for those who don't allow them to
disable/enable the feature.  Sooner or later those who don't will be in the
boat of those who do.  Engeineer CMake for the most common denominator not
the least common denominator that way we can get the most out of CMake.

-snip-
How will the loader load the correct DLL if they've got the same name?
-end snip-

Save the asprin and name mangle the dlls as boost does.

-snip-
even Boost's crazy naming schemes can be found _most_ of the time.
-end snip-

Boost guys have it figured out.  This is why I recommended the switch to
Boost.Build over GNU Make for embedded system development.  I guess you have
to be a little "crazy" to redefine the C++ standard.

--snip--
   So here is what really happens with Visual Studio. When you invoke CMake
you select to build "Shared" libraries and a Win64 application. These are
the basics. Visual Studio will create a subdirectory for "Debug" and
"Release" variants for you. So when you build you get a shared library with
debug symbols placed in the Build/Debug/ directory and the same for Release
(Build/Release). Now. since these are completely separate directories when
you execute your program the correct libraries will be found. Great. This
falls apart if you "install" your project to a location for other projects
to get to. Then one library will over write the other.
--end snip--

--snip--
  In a typical CMake workflow one would create another build directory and
rerun CMake again to generate another Visual Studio solution that would have
say a 32 bit Static build in it. This is what CMake kind of expects. You can
abuse this if you want. Take a look at the boost-cmake project.
--end snip-

Cmake should expect more from itself.  Boost is not abuse!  It's the way of
the future.  boost-cmake is the closest thing to sanity I have seen in CMake
projects and is the only one I can tightly integrate with in my projects
using add_subdirectory.  So they are doing something right.

--snip--
   Since I use Qt for my apps and they have a set way of doing things and
since CMake can find those libraries in both Debug and Release variants then
I modeled my own projects so they produce the same type of naming scheme as
Qt. This allows me to install both a Debug and Release version into a
location where other projects can find them, say C:\Developer\i386\MyProject
or C:\Developer\x64\MyProject.
--end snip--

I only whish CMake had a model.  Not just a loose collection of build
functions so I can create my own model, which is fine for wheel reinvention
or if I need to get CMake to do something specific.

--snip--
  If you want to go even further and decorate your library names like boost
does then go ahead and write the CMake code (or grab it from the Boost-cmake
project).
--end snip-

Yes grab it from BoostCore.cmake and post it to CMake as a feature
request... Please!

--snip--
 CMake only needs to do what the other platforms do which is NOT decorate
the library names. VS does not do this by default. Xcode does not. Eclipse
does not. Makefiles do not (unless you write it to). SO that is why CMake
does not do it.
--end snip-

Lets not confuse editor/debugger  tools with how the build tool should
work.  If we are all going to rely on what VS is capable of then we are
doomed as programmers.  I might as well throw in my debugger and become a
Shrimp Boat Captain.  Eclipse dose not?  Eclipse does not with Makefiles...
Eclipse DOES with bjam which worked great for me for 3 years.  VS not so
much.  CMake needs to do what the programmer needs it to do not what some
crappy platform/code editor tool expects.  Even in VS I am forcing CMake and
VS to do my bidding using my wierding ways.  I also use Eclipse+VS+CMake.
As for "Makefiles do not" we started out writing them to then just switched
to a build system that did it by default... Boost.Build bjam!

--snip--
  You _can_ very easily do this if you want. The code is out there in the
wild in the form of macros that can be invoked from CMake that will set all
of this up for you. You just have to look for it (or ask the right person...
)
--end snip--

Is there a secret handshake too? :-) I just wish this was a part of CMake
with a couple of examples for thoes of us "crazy" enough to want this
feature.

I think what we will find that if this is not implemented as part of some
standard of CMake use then third party library creators will not implement
it and when it is needed by the programmer who does they will be stuck
rewriting the third party developer build system.  Case in point:

--snip--
Yes, it was done already (For some of them) which is what I started with.
But what you find is that the CMake files that someone wrote are kinda
"tweaked" for their project and don't really work for yours so you end up
forking the project, pushing it into your own source repo and fixing the
problems. Exacerbating this issue is that some upstream developers want
NOTHING to do with CMake and so will NOT add the CMake files to their
projects. So you are stuck keeping your own pathced versions. Is this what
is optimal nope but this is what we get.
 I thought there was some sort of project setup which aimed to keep a
separate patch for some of the major opensource projects where the original
source would be downloaded then patched with the cmake files thus creating a
"CMakeified" version of the library. Can not remember what the name of the
project was. I think it was hosted at google code.
--end snip--

-snip-
Why is this abuse?
Because it circumvents CMakes generally accepted practice of a single type
of configuration per build directory. I guess "abuse" is subject to each
different person.
-end snip-

It's not abuse. I wonder if there was a statictical sampling for "generally
accepted practice".  I sure don't agree with it.  I must have been in the
"minority" district with the conveniently malfunctioning voting machine when
the poll was taken.  It's that frigging Electoral College thing again isn't
it! :-)

I think CMake could use:

1) standard name mangling which was flexible enough to be turned on and off
and implemented by Third Party Package developers perhaps with out them even
realizing it
2) better support for integrating Third Party Packages using
add_subdirectory.  For what I mean google "Build only what you need in third
party libs" or see
http://www.cmake.org/pipermail/cmake/2010-January/034908.html
3) elimination of the use of GLOBAL CMAKE_C_FLAGS and friends
4) Addition of projects (I don't know what the current "project" concept in
CMake is useful for... yes I know for specifying the language/build tool..
but it stops there) and project inheritacne vs subdirectory inheritace of
build settings.  I am currently trying to flush this out and will post my
successes/failures.
5) An "Easy Button"... well I can ask can't I? :-)

I have currently gone by the way of boost in calling macros/functions (which
I am currently refining) for generating my projects such as:

-snip CMakeLists.txt-
add_gpu_matlab_mex_library(
    gpuPMatrixRecon
    CPP_SOURCES
        gpuPMatrixRecon.cpp
        CUDADeviceProperties.cpp
#    CU_SOURCES  gpuPMatrixRecon.cu
    DEFINES CUDADeviceProperties_DLLExport=yes GPU_RECON=yes
    MEX_ENTRY_FUNCTION yes
)
-end snip--


-snip add_gpu_matlab_mex_library.cmake -
#macro( add_gpu_matlab_mex_library LIB_NAME )
function( add_gpu_matlab_mex_library LIB_NAME )

    PARSE_CMAKE_ARGUMENTS(ARG

"SRCDIRS;INCLUDE_DIRS;CPP_SOURCES;CU_SOURCES;LINK_LIBS;DEFINES;DLL_EXPORT_FUNCTIONS;MEX_ENTRY_FUNCTION;VTK_ENABLED"
""
        ${ARGN}
    )

    message("Generating mex/cuda library ${LIB_NAME}" )
    message("\tARG_SRCDIRS = ${ARG_SRCDIRS}" )
    message("\tARG_CPP_SOURCES = ${ARG_CPP_SOURCES}" )
    message("\tARG_CU_SOURCES = ${ARG_CU_SOURCES}" )
    message("\tARG_LINK_LIBS= ${ARG_LINK_LIBS}")
    message("\tARG_MEX_ENTRY_FUNCTION= ${ARG_MEX_ENTRY_FUNCTION}")

    cmake_minimum_required(VERSION 2.8)

#    SET( MATLAB_CUDA_MEX_NAME ${LIB_NAME} )

    SET( MATLAB_CUDA_FILES ${ARG_CU_SOURCES} ${ARG_CPP_SOURCES} )

    set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS 1)


    INCLUDE_DIRECTORIES(
        ./
    )

    if(DEFINED ARG_INCLUDE_DIRS)
        foreach( INCLUDE_DIR ${ARG_INCLUDE_DIRS} )
            INCLUDE_DIRECTORIES( ${INCLUDE_DIR} )
        endforeach()
    endif()


    LINK_DIRECTORIES(
        ${MATLAB_LIBRARIES}
        ${MATLAB_MEX_LIBRARY}
        ${MATLAB_MX_LIBRARY}
        ${MATLAB_ENG_LIBRARY}
        "${TOP}/build/dvip4-Win64/lib/Debug"
    )

    if(DEFINED ARG_VTK_ENABLED )
        message( "\tEnabling VTK" )

        LINK_DIRECTORIES(
            ${CMAKE_INSTALL_PREFIX}/lib
            ${CMAKE_INSTALL_PREFIX}/lib/vtk-${VTK_LIB_VERSION_INCLUDE}
            ${CMAKE_INSTALL_PREFIX}/lib/VTKEdge
        )

        SET(
            VTK_LIBS
            vtkCommon
            vtkDICOMParser
            vtkFiltering
            vtkGraphics
            vtkImaging
            vtkIO
            vtkRendering
            vtkVolumeRendering
        )

        SET( VTKEDGE_LIBS
            vtkKWECommon
            vtkKWEVolumeRendering
        )
    endif()

    SET( MATLAB_LINK_LIBS
        libmx
        libmex
        libmat
    )



    SET( ${CUDA_LIBRARIES}
        cudart
        cuda
        cublas
        cublasemu
    )


    foreach( DEFINE_STR ${ARG_DEFINES} )
        message("\tDEFINE_STR = ${DEFINE_STR}" )
        add_definitions( -D${DEFINE_STR} )
    endforeach()


    if(DEFINED ARG_CU_SOURCES )
        message("\tARG_CU_SOURCES is defined as = ${ARG_CU_SOURCES}" )
        CUDA_ADD_LIBRARY( ${LIB_NAME} SHARED ${MATLAB_CUDA_FILES} )
    else()
         message("\tARG_CU_SOURCES is not defined" )
         message("\tdefining library ${LIB_NAME} with sources
${ARG_CPP_SOURCES}")
        ADD_LIBRARY( ${LIB_NAME} SHARED ${ARG_CPP_SOURCES} )
    endif()

    TARGET_LINK_LIBRARIES( ${LIB_NAME}
        ${MATLAB_LINK_LIBS}
        ${CUDA_LIBRARIES}
        ${ARG_LINK_LIBS}
    )

    if(DEFINED ARG_VTK_ENABLED )
        TARGET_LINK_LIBRARIES( ${LIB_NAME}
            ${VTK_LIBS}
            ${VTKEDGE_LIBS}
        )
    endif()


    if(DEFINED ARG_MEX_ENTRY_FUNCTION)
        message("\tExporting MEX entry function" )
        SET_TARGET_PROPERTIES( ${LIB_NAME} PROPERTIES
          SUFFIX .mexw64
           LINKER_LANGUAGE CXX
          LINK_FLAGS /export:mexFunction
          )
    else()
        message("\tNot exporting MEX entry function" )
    endif()


    if(DEFINED ARG_DLL_EXPORT_FUNCTIONS )
        message("\tExporting functions ${ARG_DLL_EXPORT_FUNCTIONS}" )
        foreach( FUNCTION_NAME ${ARG_DLL_EXPORT_FUNCTIONS} )
            message("\t\t Exporting ${FUNCTION_NAME}" )
            SET_TARGET_PROPERTIES( ${LIB_NAME} PROPERTIES
              LINK_FLAGS /export:${FUNCTION_NAME}
              )
        endforeach()
    else()
    endif()

    INSTALL( TARGETS ${LIB_NAME} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR} )

    INSTALL( TARGETS ${SQUARE_ME_TEST_APP}
        DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}
    )




#endmacro()
endfunction()

--end snip--

As you can see it is a work in progress as I have not added the LINK_LIBS
feature for the vtk goop.  Anyway I do this due to the verbosity of the
CMake Syntax to preform meaningful work.  I started out using the simpletons
approach of having verbose CMakeLists.txt files for each lib..  Then I "got
smart" or dumber to the point I think I am smart... not sure which.

I am working to add concept of Project Inheritance to these macros.

What makes this possible is PARSE arguments which is strangely not apart of
CMake, which I found in boost and also here
http://www.cmake.org/Wiki/CMakeMacroParseArguments.  Talk about wheel
reinvention... you know on the topic I have this concept for this Octagonal
wheel to increases fuel efficiency... you get the idea.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.cmake.org/pipermail/cmake/attachments/20100723/f54d1c9c/attachment-0001.htm>


More information about the CMake mailing list