Proposing some build system improvements

Apr 10, 2012 at 3:34 PM
Edited Apr 16, 2012 at 8:18 AM

@Jan de Vaan: Thank you for resolving so quickly the issue with the separation of public and private headers as well the compilation problems in test/main.cpp. Now I can build the library without local code modifications and I can distribute it with only a few public headers. It is even possible to automate the extraction of the public headers to the installation folder. In this connection I want to contribute a slightly improved version of the CMakeList.txt file which offers the following additional features:

  • outputs the generated test exe into Binaries/bin/ and libraries into Binaries/lib/ created inside the build directory

  • generates “make install” target which on non-windows platforms is able to install the generated binaries as well the public headers into prefix dir specified with CMAKE_INSTALL_PREFIX like for example -DCMAKE_INSTALL_PREFIX:PATH=/opt/charls-svn

  • resolves the naming conflict between the static library and dll import library for windows platform which make possible to they co-exist (therefore to be built and installed) into a single directory.

  • On windows platform the .rc file is linked to the library in order to add version and licensing information. (With the original cmake file the resource file was not build and linked, at least for command line builds.) On unix platforms versioning is achieved with sonames. A symbolic links to the latest installed version shared library are automatically created.

  • On Unix x86_64 forces Position Independent Code generation also for the static library. This makes possible to link a static version of CharLS library build on this platform as a component in another (application specific) shared libraries.

I had to add these modifications to the CmakeList.txt file because I have to build and install CharLS library on multiple platforms (Linux, Windows, OS X) and with multiple compilers (gcc-4.1, 4.2, 4.3, 4.4, VS 8.0, 9.0, 10.0) both release and debug versions and both x86_64 and i386 targets. I am not a cmake expert but this cmake file save me a lot's of manual work and probably it could be also useful for some other users of CharLS library and Linux package maintainers.

 

PROJECT(charls)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)

SET(CHARLS_LIB_MAJOR_VERSION 1)
SET(CHARLS_LIB_MINOR_VERSION 0)

IF(NOT CMAKE_BUILD_TYPE)
  SET( CMAKE_BUILD_TYPE Release CACHE STRING
       "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
       FORCE )
ENDIF(NOT CMAKE_BUILD_TYPE)


# Set where the binary files will be built.  The program will not execute from
# here.  You must run "make install" to install these to the proper location
# as defined above.
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Binaries/bin)
SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/Binaries/lib)
SET(ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Binaries/lib)

OPTION(CharLS_BUILD_SHARED_LIBS "Build CharLS with shared libraries." OFF)
SET(BUILD_SHARED_LIBS ${CharLS_BUILD_SHARED_LIBS})

SET( CharLS_PUBLIC_HEADERS "interface.h" "publictypes.h" "config.h" )
SET( CharLS_LIBRARY_SOURCES header.cpp interface.cpp jpegls.cpp stdafx.cpp )

ADD_EXECUTABLE(charlstest test/main.cpp test/time.cpp test/util.cpp test/bitstreamdamage.cpp test/compliance.cpp test/performance.cpp test/dicomsamples.cpp)

SET(TARGETS_LIST ${charlstest} )

IF(WIN32)
  IF(BUILD_SHARED_LIBS)
    ADD_DEFINITIONS(-D CHARLS_DLL)
  ELSE(BUILD_SHARED_LIBS)
    ADD_DEFINITIONS(-D CHARLS_STATIC)
  ENDIF(BUILD_SHARED_LIBS)

  # Make sure that the resource file is seen as an RC file to be compiled
  # with a resource compiler and not with a C++ compiler
  SET_SOURCE_FILES_PROPERTIES( ${CMAKE_SOURCE_DIR}/charls.rc LANGUAGE RC )
  # Under Windows, we also include a resource file to the list of sources
  LIST( APPEND CharLS_LIBRARY_SOURCES ${CMAKE_SOURCE_DIR}/charls.rc )

  # For MinGW, we have to change the compile flags
  IF(MINGW)
    SET( CMAKE_RC_COMPILER_INIT windres )
    ENABLE_LANGUAGE(RC)
    SET( CMAKE_RC_COMPILE_OBJECT
         "<CMAKE_RC_COMPILER> <FLAGS> <DEFINES> -i <SOURCE> -o <OBJECT>" )
    SET( RC_CFLAGS "-DMINGW -Ocoff" )
    SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/charls.rc COMPILE_FLAGS "${RC_CFLAGS}")
  ENDIF(MINGW)
ENDIF(WIN32)

# without next block we would be unable to link CharLS static library to
# other shared libraries
IF(UNIX)
  IF(CMAKE_COMPILER_IS_GNUCXX)
    IF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
      SET( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC" )
      SET( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fPIC" )
      SET( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -fPIC" )
      SET( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} -fPIC" )
    ENDIF(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64")
  ENDIF(CMAKE_COMPILER_IS_GNUCXX)
ENDIF(UNIX)

IF ( BUILD_SHARED_LIBS )
  MESSAGE( "Going to build CharLS as shared library." )
  ADD_LIBRARY(CharLS SHARED ${CharLS_LIBRARY_SOURCES} )

  # This has no effect with MSVC, on that platform the version info for
  # the DLL should come from resource (.rc) file.
  SET_TARGET_PROPERTIES( CharLS PROPERTIES
                         VERSION ${CHARLS_LIB_MAJOR_VERSION}.${CHARLS_LIB_MINOR_VERSION}
                         SOVERSION ${CHARLS_LIB_MAJOR_VERSION}
  )
  TARGET_LINK_LIBRARIES( charlstest CharLS )
  INSTALL_TARGETS( /lib CharLS )
ELSE ( BUILD_SHARED_LIBS )
  MESSAGE( "Going to build CharLS as static library." )
  MESSAGE( "If you want shared CharLS library define -DCharLS_BUILD_SHARED_LIBS:BOOL=ON" )
  ADD_LIBRARY(CharLS-static STATIC ${CharLS_LIBRARY_SOURCES} )

  # The library target "CharLS" already has a default OUTPUT_NAME of "CharLS", so we don't need to change it.
  # The library target "CharLS-static" has a default OUTPUT_NAME of "CharLS-static", so change it.
  SET_TARGET_PROPERTIES(CharLS-static PROPERTIES OUTPUT_NAME "CharLS")
 
  # Now the library target "CharLS-static" will be named "CharLS.lib" with MS tools.
  # This conflicts with the "CharLS.lib" import library corresponding to "CharLS.dll",
  # so we add a "lib" prefix (which is default on other platforms anyway):
  SET_TARGET_PROPERTIES(CharLS-static PROPERTIES PREFIX "lib")
  TARGET_LINK_LIBRARIES( charlstest CharLS-static )
  INSTALL_TARGETS( /lib CharLS-static )
ENDIF ( BUILD_SHARED_LIBS )

INSTALL_TARGETS( /bin charlstest )

# Installs the header files into the {build_dir}/include/CharLS directory
INSTALL(FILES ${CharLS_PUBLIC_HEADERS} DESTINATION include/CharLS)