[CMake] Testing and DLLs

Michael Jackson mike.jackson at bluequartz.net
Wed May 4 12:25:04 EDT 2011


Funny, I did the same thing using pure CMake code because I couldn't figure out batch files. 

# --------------------------------------------------------------------
#-- Copy all the dependent DLLs into the current build directory so that the test
#-- can run.
MACRO (CMP_COPY_DEPENDENT_LIBRARIES _libraryList)
#  message(STATUS "#--------------------------------------------")
#  message(STATUS "CMP_COPY_DEPENDENT_LIBRARIES: ${_libraryList}")
  set (_libraryList ${_libraryList})
  SET (TYPES Debug Release)
  if (MSVC)
    # Make all the necessary intermediate directories for Visual Studio
    file(MAKE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Debug)
    file(MAKE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Release)
    file(MAKE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MinSizeRel)
    file(MAKE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/RelWithDebInfo)
    FOREACH(lib ${_libraryList})
    
      STRING(TOUPPER ${lib} upperlib)
     # message(STATUS "upperlib: ${upperlib}")
     # message(STATUS "${upperlib}_IS_SHARED: ${${upperlib}_IS_SHARED}")
      if (${upperlib}_IS_SHARED)
        FOREACH(BTYPE ${TYPES} )
        #  message(STATUS "Looking for ${BTYPE} DLL Version of ${lib}")
          STRING(TOUPPER ${BTYPE} TYPE)        
          get_filename_component(lib_path ${${upperlib}_LIBRARY_${TYPE}} PATH)
          get_filename_component(lib_name ${${upperlib}_LIBRARY_${TYPE}} NAME_WE)
       #   message(STATUS "lib_path: ${lib_path}")
       #   message(STATUS "lib_name: ${lib_name}")
          
          find_file(${upperlib}_LIBRARY_DLL_${TYPE}
                        NAMES ${lib_name}.dll
                        PATHS  ${lib_path}/../bin ${lib_path}/.. ${lib_path}/ ${${upperlib}_BIN_DIR}
                        NO_DEFAULT_PATH )
      #    message(STATUS "${upperlib}_LIBRARY_DLL_${TYPE}: ${${upperlib}_LIBRARY_DLL_${TYPE}}")
          mark_as_advanced(${upperlib}_LIBRARY_DLL_${TYPE})
          if ( ${${upperlib}_LIBRARY_DLL_${TYPE}} STREQUAL  "${upperlib}_LIBRARY_DLL_${TYPE}-NOTFOUND")
            message(FATAL_ERROR "According to how ${upperlib}_LIBRARY_${TYPE} was found the library should"
                                " have been built as a DLL but no .dll file can be found. I looked in the "
                                " following locations:\n  ${lib_path}\n  ${lib_path}/..\n  ${lib_path}/../bin\n  ${${upperlib}_BIN_DIR}")
          endif()

         # SET(${upperlib}_LIBRARY_DLL_${TYPE} "${${upperlib}_LIBRARY_DLL_${TYPE}}/${lib_name}.dll" CACHE FILEPATH "The path to the DLL Portion of the library" FORCE)
         # message(STATUS "${upperlib}_LIBRARY_DLL_${TYPE}: ${${upperlib}_LIBRARY_DLL_${TYPE}}")
          message(STATUS "Generating Copy Rule for ${BTYPE} DLL Library ${${upperlib}_LIBRARY_DLL_${TYPE}}")
          ADD_CUSTOM_TARGET(ZZ_${upperlib}_DLL_${TYPE}-Copy ALL 
                      COMMAND ${CMAKE_COMMAND} -E copy_if_different ${${upperlib}_LIBRARY_DLL_${TYPE}}
                      ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${BTYPE}/ 
                      COMMENT "  Copy: ${${upperlib}_LIBRARY_DLL_${TYPE}}\n    To: ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${BTYPE}/")

        ENDFOREACH(BTYPE ${TYPES})
      ENDIF(${upperlib}_IS_SHARED)
    ENDFOREACH(lib ${_libraryList})
  ENDIF(MSVC)  
endmacro()

This does depend on certain CMake variables being setup correctly though so maybe the batch file solution might work better. 

___________________________________________________________
Mike Jackson                      www.bluequartz.net
Principal Software Engineer       mike.jackson at bluequartz.net 
BlueQuartz Software               Dayton, Ohio

On May 4, 2011, at 11:52 AM, John Drescher wrote:

>> I am curious whether there is a common way of dealing with unit tests
>> when the actual project to be tested is a DLL? The issue I am facing
>> is a common Windows issue where the required DLL is not found in the
>> path.
>> 
>> I tried to put all binaries in the same directory by modifying
>> CMAKE_*_OUTPUT_DIRECTORY but that did not affect my tests (added via
>> add_test).
>> 
>> Another solution I can think of is running "make INSTALL" before
>> running the tests but that feels like a strange approach since I
>> typically want to test before installing.
>> 
>> Its also not really possible to adapt the PATH environment variable -
>> how could I possible guess where somebody is going to build my code!?
>> 
>> So again, I am really curious if there is a well working solution.
>> 
> 
> I now have a custom build script that generates a batch file that
> copies (using cmake commands) the required dlls into the Debug,
> Release, RelWithDebInfo folders for me for the few libraries that
> require dlls (Qt ). For ITK, VTK ... I use static libs so no need to
> copy these.
> 
> 
> 
> 
> 
> option (GET_RUNTIME			"Create a target that will get the runtime" ON)
> 
> IF (GET_RUNTIME)
> 
> 	SET (${PROJECT_NAME}_PACKAGING_RUNTIME "")
> 
> 	SET (RUNTIME_BATCH_FILENAME "${PROJECT_BINARY_DIR}/GetRuntime.bat"
> CACHE FILEPATH "${PROJECT_BINARY_DIR}/GetRuntime.bat")
> 	
> 	add_custom_target(GetRuntime  "${RUNTIME_BATCH_FILENAME}")
> 	
> #########################################################################################
> 
> 	macro( add_runtime_file BatchFileName RuntimeFile Configuration )
> 
> 		# Test if this is a valid configuration.
> 		STRING( REGEX MATCH ${Configuration} __MATCHED__ ${CMAKE_CONFIGURATION_TYPES})
> 		if ( NOT "${__MATCHED__}" STREQUAL "" )
> 		
> 			IF (NOT EXISTS "${EXECUTABLE_OUTPUT_PATH}/${Configuration}")
> 				file( MAKE_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}/${Configuration}" )
> 			ENDIF (NOT EXISTS "${EXECUTABLE_OUTPUT_PATH}/${Configuration}")
> 		
> 			GET_FILENAME_COMPONENT( BatchFile ${BatchFileName} NAME_WE )
> 			
> 			#The following will truncate the file on the first call to add_runtime_file.
> 			if ( NOT DEFINED __add_runtime_file_${BatchFile}__ )
> 				set ( __add_runtime_file_${BatchFile}__ 1)
> 				file( WRITE ${BatchFileName} "REM This file will copy the runtimes
> to the Debug and Release binary folders\n" )
> 			endif ( NOT DEFINED __add_runtime_file_${BatchFile}__)
> 			
> 			#The following line will add the entry in the batch file for
> copying the Runtime file to the folder
> ${PROJECT_BINARY_DIR}/${Configuration}/
> 			file( APPEND ${BatchFileName} "\"${CMAKE_COMMAND}\" -E
> copy_if_different \"${RuntimeFile}\"
> \"${EXECUTABLE_OUTPUT_PATH}/${Configuration}/\"\n" )
> 		endif(  NOT "${__MATCHED__}" STREQUAL "" )
> 	endmacro( add_runtime_file )
> 	
> #########################################################################################
> 
> 	macro( add_runtime_file_for_packaging RuntimeFile )
> 		SET( ${PROJECT_NAME}_PACKAGING_RUNTIME
> ${${PROJECT_NAME}_PACKAGING_RUNTIME} ${RuntimeFile} )
> 	endmacro( add_runtime_file_for_packaging )
> 	
> ENDIF(GET_RUNTIME)
> _______________________________________________
> Powered by www.kitware.com
> 
> Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html
> 
> Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ
> 
> Follow this link to subscribe/unsubscribe:
> http://www.cmake.org/mailman/listinfo/cmake



More information about the CMake mailing list