0

The folder structure:

Project/
├── main.cpp
└── deps/
    └── FreeImage/
        ├── FreeImage.lib
        ├── FreeImage.dll
        ├── FreeImage.h
        ├── FreeImagePlus.lib
        ├── FreeImagePlus.dll
        └── FreeImagePlus.h

The code:

#include <FreeImagePlus.h>

int main(void)
{
    fipImage i;
    return 0;
}

And now the question:

How to write a CMakeLists.txt file to be able to compile the above in windows?

My attempt as an answer below

WurmD
  • 1,231
  • 5
  • 21
  • 42
  • 2
    I'm voting to close this question as off-topic because SO is not a free code-writing service (including writing build system scripts). At a minimum, show us what you have tried so far. – Jesper Juhl Apr 02 '19 at 15:52
  • You could add it as [imported library](https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries) (that you then [link with normally](https://cmake.org/cmake/help/latest/command/target_link_libraries.html)) and [add the directory as an include directory](https://cmake.org/cmake/help/latest/command/include_directories.html). – Some programmer dude Apr 02 '19 at 16:02
  • 1
    BTW, lt looks like vcpkg has FreeImage: https://github.com/Microsoft/vcpkg/tree/master/ports/freeimage you may want to take a look at the [CMakeLists.txt](https://github.com/Microsoft/vcpkg/blob/master/ports/freeimage/CMakeLists.txt) that they developed. – drescherjm Apr 02 '19 at 16:10
  • @drescherjm , vcpkg compiles the library from scratch, not the intented for this question – WurmD Apr 02 '19 at 17:01
  • @Someprogrammerdude do you recommend "add_library(...); target_link_libraries(...);" vs simply the target_link_libraries I put in my answer below? – WurmD Apr 02 '19 at 17:05
  • See also that question https://stackoverflow.com/questions/8774593/cmake-link-to-external-library/8776420 and answers to it. – Tsyvarev Apr 02 '19 at 20:20
  • 1
    @WurmD That adds the library as a target, you can then add or set properties for that target (like dependencies) easily, and reuse it with those properties already set if needed. Possibly a combination of `find_package` (as suggested by Matthieu Brucher) and `add_library`. While a specific solution might work well in this case, making it more generic means you can reuse it and customize it more easily in the future. – Some programmer dude Apr 02 '19 at 22:36

2 Answers2

1

You should use different steps here. A proper goal is to have everything you need to use FreeImage in a FindFreeImage.cmake file. Then you can set FreeImage.cmake like this:

FIND_PATH(FreeImage_INCLUDE_DIR FreeImage.h HINTS ${FreeImage_ROOT})

FIND_LIBRARY(FreeImage_LIBRARY NAMES FreeImage HINTS ${FreeImage_ROOT})

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(FreeImage DEFAULT_MSG FreeImage_INCLUDE_DIR FreeImage_LIBRARY)

Of course, you should add more so that when linking against FreeImage, you get the include path set, installation procedure... But that would be for another question.

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
  • 1
    I'd like to add that you can take this a step further and add an import target (i.e. `add_library(FreeImage::FreeImage SHARED IMPORTED)` and then you can set the include path, lib path and dll path using `set_target_properties()`. Finally, you can link to your main project using `target_link_libraries(MyProject PUBLIC FreeImage::FreeImage)`. – Developer Paul Apr 03 '19 at 12:17
-1

One solution of a CMakeLists.txt with extra tips

cmake_minimum_required(VERSION 3.8)

set(NAME cmakecopytest)

project(${NAME})

# The place to put built libraries
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin/windows-64/debug")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin/windows-64/debug")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}/bin/windows-64/debug")

# Copying pre-compiled dll libraries next to the built libraries for them to be found in runtime without extra effort
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/deps/FreeImage/FreeImagePlus.dll" "${CMAKE_BINARY_DIR}/bin/windows-64/debug/FreeImagePlus.dll" COPYONLY)    
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/deps/FreeImage/FreeImage.dll" "${CMAKE_BINARY_DIR}/bin/windows-64/debug/FreeImage.dll" COPYONLY)

add_executable(${NAME}_exe main.cpp)

target_include_directories(${NAME}_exe PUBLIC ./ include/ deps/FreeImage)

target_link_libraries(${NAME}_exe PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/deps/FreeImage/FreeImage.lib" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/deps/FreeImage/FreeImagePlus.lib")
# target_link_libraries(${NAME}_exe PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/deps/FreeImage/FreeImage" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/deps/FreeImage/FreeImagePlus") # ERROR LNK1104: cannot open file '..\deps\FreeImage\FreeImage.obj'

Extra tips:

  • CMAKE_BINARY_DIR contains the place where you built the solution (i.e., D:/Work/Project/build)
  • Setting the output directories and then copying the precompiled libraries to that same location is a easy way to have your code run without any added extra configurations in MSVS

    math(EXPR platform_bits "${CMAKE_SIZEOF_VOID_P} * 8")
    set(platform_dir bin/${CMAKE_SYSTEM_NAME}-${platform_bits})
    foreach(config DEBUG RELEASE RELWITHDEBINFO MINSIZEREL)
        foreach(var
                CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${config}
                CMAKE_LIBRARY_OUTPUT_DIRECTORY_${config}
                CMAKE_RUNTIME_OUTPUT_DIRECTORY_${config}
                )
            set(${var} "${CMAKE_BINARY_DIR}/${platform_dir}/${config}")
            string(TOLOWER "${${var}}" ${var})
            configure_file(${CMAKE_CURRENT_SOURCE_DIR}/deps/FreeImage/FreeImagePlus.dll ${var}/FreeImagePlus.dll COPYONLY)
            configure_file(${CMAKE_CURRENT_SOURCE_DIR}/deps/FreeImage/FreeImage.dll ${var}/FreeImage.dll COPYONLY)            
        endforeach()
    endforeach()
    
  • And this for cycle does that for you for all the desired configurations

However, I do not like having to specify the '.lib' in target_link_libraries(...FreeImage.lib...)

Anyone else has a solution to be able to say target_link_libraries(${NAME}_exe PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/deps/FreeImage/FreeImage" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/deps/FreeImage/FreeImagePlus") while avoiding the linking error LNK1104: cannot open file '..\deps\FreeImage\FreeImage.obj' ?

WurmD
  • 1,231
  • 5
  • 21
  • 42