CMake - compile with /MT instead of /MD - visual-studio-2012

I'm a newbie to cmake (2.8.12.1) and I'm using it on Windows to generate the project files to build cpp-netlib using Visual Studio 2012.
By default it compiles with the /MDd compiler switch. I want to change it so that it uses /MTd.
I followed the advice given here https://stackoverflow.com/a/14172871 but it isn't working for me.
Specifically, I added the second line shown below in the if statement to CmakeLists.txt.
if (MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
endif()
When I open the Visual Studio sln file I can see that the /MDd option is still set. Furthermore, I see the following in CMakeCache.txt:
//Flags used by the compiler during debug builds.
CMAKE_CXX_FLAGS_DEBUG:STRING=/D_DEBUG /MDd /Zi /Ob0 /Od /RTC1
I've also tried setting the flags from scratch like this:
set(CMAKE_CXX_FLAGS_DEBUG "/MTd")
but that doesn't work either.
If I pass the option via the command line like this:
-DCMAKE_CXX_FLAGS_DEBUG="/MTd"
the option is successfully set in the Visual Studio projects.
Can anyone tell me what I'm doing wrong?
I would also appreciate it if someone could enlighten me as to where the values in the cache come from that I don't specify on the command line or aren't in CmakeLists.txt.
Adding CMakeList.txt as requested. I've never posted before so apologies if I've not done this right.
# Original from cpp-netlib.org with my edits
cmake_minimum_required(VERSION 2.8)
project(CPP-NETLIB)
set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTI_THREADED ON)
find_package( Boost 1.45.0 REQUIRED unit_test_framework system regex date_time thread filesystem program_options chrono )
find_package( OpenSSL )
find_package( Threads )
set(CMAKE_VERBOSE_MAKEFILE true)
if (CMAKE_BUILD_TYPE MATCHES Debug)
add_definitions(-DBOOST_NETWORK_DEBUG)
endif()
if (OPENSSL_FOUND)
add_definitions(-DBOOST_NETWORK_ENABLE_HTTPS)
include_directories(${OPENSSL_INCLUDE_DIR})
endif()
if (${CMAKE_CXX_COMPILER_ID} MATCHES GNU)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
endif()
if (Boost_FOUND)
################# added #################
add_definitions(-DBOOST_ALL_NO_LIB)
#########################################
if (MSVC)
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
endif(MSVC)
if (WIN32)
add_definitions(-D_WIN32_WINNT=0x0501)
endif(WIN32)
include_directories(${Boost_INCLUDE_DIRS})
enable_testing()
add_subdirectory(libs/network/src)
add_subdirectory(libs/network/test)
if (NOT MSVC)
add_subdirectory(libs/mime/test)
endif(NOT MSVC)
add_subdirectory(libs/network/example)
endif(Boost_FOUND)
if (MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
################# added #################
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd")
#########################################
endif()
enable_testing()

Adding the code inside your if block should work fine. However, since it doesn't produce the required effect in your .sln, either the code inside the if block isn't being executed or the flags are being replaced later in the CMakeLists.txt.
As to where the cached values for these flags come from; CMake applies and caches what are considered to be useful default values for each default build type.
Have you added your changes to the flags before the project call? project sets up a lot of things, including the compiler flags. If you set these flags without caching them (i.e. calling set as you have shown), project will overwrite them. If you set the flags and cache them (e.g. using set(... CACHE), or by adding them via the command line arg -D as you have shown), then project won't overwrite them.
Also, since calling set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") doesn't use the CACHE option of set, then this change to the variable CMAKE_CXX_FLAGS won't appear in your CMakeCache.txt file.
In order to get this into the cache, you'd have to also use the FORCE option of set, since you'd be telling CMake to replace an already-cached value (CMake itself caches these flag variables by default). I wouldn't recommend this however - I can't see why you'd need to do this, and you'd be best to look for a better way than appending the flag(s) you want, since every time CMake runs the appended flags would be re-appended.
If this doesn't allow you to resolve your issue, perhaps you could show a full (small) CMakeLists.txt which exhibits the problem?
UPDATE:
OK - The problem is a scoping issue. The changes to the compiler flags will be applied to all targets (exes/libs) which are defined in that CMakeLists.txt, but only to subdirectory targets which are added after the flags are modified.
The add_subdirectory command introduces a new scope (although this isn't mentioned in the docs) which inherits a copy of the parent's variables. However, subsequent changes to the variables in the parent scope don't affect the child copies, and likewise changing the child copies doesn't affect the value of the parent's copies (unless you force it using set(... PARENT_SCOPE)).
So, to fix your issue, just move the if(MSVC) block to before all the add_subdirectory calls.

Related

CMake Precompiled Headers not including correctly for Visual Studio

So I've recently started using the "new" target_precompile_headers command for CMake to generate and include my precompiled headers.
But for some reason it doesn't seem to work at all the way I want it.
I do understand that the usage of this command is to provide the list of headers to include in your pch and that CMake itself generates the actual pch. This seem to work just fine as I can see the pchs generated for each config & project in my solution.
However looking at the project properties, and more specifically looking at the .cpp properties the /FI command is always empty, which means no files are force included.
This also means that none of my cpp catches that I am using pch at all and my compile fails.
Does anyone have any suggestions on what could be wrong?
// Example of a CMakeLists.txt which defines a static lib using PCH
file(GLOB ALL_SOURCE_FILES "*.cpp" "*.h")
add_library(MyLib STATIC ${ALL_SOURCE_FILES})
target_precompile_headers(MyLib PRIVATE MyHeader.h)
Below you see my own lib created with the snippet above. As you can see, no Forced Include file is added, thus no cpp files gets the PCH included.
I found this workaround: Adding the compiler option manually...
if(MSVC)
target_compile_options(YourProject PRIVATE "/FI${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${PROJECT_NAME}.dir/$<CONFIG>/cmake_pch.hxx")
endif()
(Currently using Cmake 3.24.1 with cmake_minimum_required(VERSION 3.18) in the file)

How to set compiler options with CMake in Visual Studio 2017

Visual Studio 2017 comes with full CMake integration. To learn about this combination, I was starting with this basic sample:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
project(foo)
add_executable(foo foo.cpp)
and
// foo.cpp
int main() {}
This properly generates build scripts, and compiles and links with no issues. That was easy.
Trying to set compiler options, on the other hand, turned out to be anything but trivial. In my case I was attempting to set the warning level to 4.
The obvious solution
add_compile_options("/W4")
didn't pan out as expected. The command line passed to the compiler now contains both /W4 (as intended) as well as /W3 (picked up from somewhere else), producing the following warning:
cl : Command line warning D9025: overriding '/W3' with '/W4'
To work around this, I would need to replace any incompatible compiler option(s) instead of just adding one. CMake does not provide any immediate support for this, and the standard solution (as this Q&A suggests) seems to be:
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
endif()
This, however, has two issues:
It sets the global CMAKE_CXX_FLAGS, applying to all C++ targets. This may not be intended (not an issue for me right now).
It doesn't scale. For every compiler option to add, you would have to read up on incompatible options, and manually strip those first. This will inevitably fail1.
My question is two-fold:
Where does the CMake integration pick up default settings from, and can this be controlled?
How do you set compiler options in general? (If this is too broad a topic, I'd be happy for help on setting the warning level only.)
1 Incidentally, the solution I replicated fails to account for the /Wall option, that is incompatible with /W4 as well.
The default settings for the compiler are picked up from standard module files located in the Modules directory of the CMake installation. The actual module file used depends on both the platform and the compiler. E.g., for Visual Studio 2017, CMake will load the default settings from the file Windows-MSVC.cmake and language specific settings from Windows-MSVC-C.cmake or Windows-MSVC-CXX.cmake.
To inspect the default settings, create a file CompilerOptions.cmake in the project directory with the following contents:
# log all *_INIT variables
get_cmake_property(_varNames VARIABLES)
list (REMOVE_DUPLICATES _varNames)
list (SORT _varNames)
foreach (_varName ${_varNames})
if (_varName MATCHES "_INIT$")
message(STATUS "${_varName}=${${_varName}}")
endif()
endforeach()
Then initialize the CMAKE_USER_MAKE_RULES_OVERRIDE variable in your CMakeLists.txt:
# CMakeLists.txt
cmake_minimum_required(VERSION 3.8)
set (CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_CURRENT_LIST_DIR}/CompilerOptions.cmake")
project(foo)
add_executable(foo foo.cpp)
When the project is configured upon opening the directory using Open Folder in Visual Studio 2017, the following information will be shown in the IDE's output window:
...
-- CMAKE_CXX_FLAGS_DEBUG_INIT= /MDd /Zi /Ob0 /Od /RTC1
-- CMAKE_CXX_FLAGS_INIT= /DWIN32 /D_WINDOWS /W3 /GR /EHsc
-- CMAKE_CXX_FLAGS_MINSIZEREL_INIT= /MD /O1 /Ob1 /DNDEBUG
-- CMAKE_CXX_FLAGS_RELEASE_INIT= /MD /O2 /Ob2 /DNDEBUG
-- CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT= /MD /Zi /O2 /Ob1 /DNDEBUG
...
So the warning setting /W3 is picked up from the CMake variable CMAKE_CXX_FLAGS_INIT which then applies to all CMake targets generated in the project.
To control the warning level on the CMake project or target level, one can alter the CMAKE_CXX_FLAGS_INIT variable in the CompilerOptions.cmake by adding the following lines to the file:
if (MSVC)
# remove default warning level from CMAKE_CXX_FLAGS_INIT
string (REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT}")
endif()
The warning flags can then be controlled by setting the target compile options in CMakeLists.txt:
...
add_executable(foo foo.cpp)
target_compile_options(foo PRIVATE "/W4")
For most CMake projects it makes sense to control the default compiler options in a rules override file instead of manually tweaking variables like CMAKE_CXX_FLAGS.
When making changes to the CompilerOptions.cmake file, it is necessary to recreate the build folder. When using Visual Studio 2017 in Open Folder mode, choose the command Cache ... -> Delete Cache Folders from the CMake menu and then Cache ... -> Generate from the CMake menu to recreate the build folder.
Turning my comment into an answer
CMake does come with some compiler switches preset. For visual studio those are mainly standard link libraries, warning levels, optimization levels, exception handling, debug information and platform specific defines.
What you now have to differentiate when you want to change a CMake generated compiler settings are the following use cases:
Additional compiler flags CMake does not define vs. changing CMake's preset settings
Project default settings vs. project user defined settings
So let's discuss common solutions for those cases.
User changes/adds to Project/CMake Compiler Flags Defaults
The standard way would be to modify the cached compiler flags variables by using tools shipped with CMake like cmake-gui and ccmake.
To achieve this in Visual Studio you would have to:
CMake / Cache / View CMakeCache
Manually change e.g. CMAKE_CXX_FLAGS to /Wall
CMakeCache.txt
//Flags used by the compiler during all build types.
CMAKE_CXX_FLAGS:STRING= /DWIN32 /D_WINDOWS /Wall /GR /EHsc
CMake / Cache / Generate
Or you preset the CMAKE_CXX_FLAGS cache variable via a CMakeSettings.json file:
CMake / Change CMake Settings
Force the cache entry with -DCMAKE_CXX_FLAGS:STRING=... in cmakeCommandArgs
CMakeSettings.json
{
// See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.
"configurations": [
{
"name": "x86-Debug (all warnings)",
"generator": "Visual Studio 15 2017",
"configurationType": "Debug",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"cmakeCommandArgs": "-DCMAKE_CXX_FLAGS:STRING=\"/DWIN32 /D_WINDOWS /Wall /GR /EHsc\"",
"buildCommandArgs": "-m -v:minimal"
}
]
}
If you deliver this CMakeSettings.json file with your CMake project it gets permanent
Project changes to CMake Compiler Flags Defaults
If you want to keep most of CMake's compiler flags in place, #sakra's answer is definitely the way to go.
For my VS projects I've put the CXX flag settings into a toolchain file coming with the project itself. Mainly to freeze those settings and don't have a dependency the CMake version used or any environment variables set.
Taking the example from above that would look like:
VS2017Toolchain.cmake
set(CMAKE_CXX_FLAGS "/DWIN32 /D_WINDOWS /Wall /GR /EHsc" CACHE INTERNAL "")
CMakeSettings.json
{
// See https://go.microsoft.com//fwlink//?linkid=834763 for more information about this file.
"configurations": [
{
"name": "x86-Debug (all warnings)",
"generator": "Visual Studio 15 2017",
"configurationType": "Debug",
"buildRoot": "${env.LOCALAPPDATA}\\CMakeBuild\\${workspaceHash}\\build\\${name}",
"cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE:FILEPATH=\"${projectDir}\\VS2017Toolchain.cmake\"",
"buildCommandArgs": "-m -v:minimal"
}
]
}
References
Visual C++ Team Blog: CMake support in Visual Studio – the Visual Studio 2017 RC update
set diagnostics:caret from CMakeLists.txt
Is Cmake set variable recursive?
Passing compiler options cmake
In CMake 3.15, CMake introduced a fix for this MSVC-specific warning:
cl : Command line warning D9025: overriding '/W3' with '/W4'
and the compiler warning flags (like /W3) are no longer automatically added. So by upgrading to CMake 3.15 or greater, this warning should no longer appear. From the docs:
When using MSVC-like compilers in CMake 3.14 and below, warning flags like /W3 are added to CMAKE_<LANG>_FLAGS by default. This is problematic for projects that want to choose a different warning level programmatically. In particular, it requires string editing of the CMAKE_<LANG>_FLAGS variables with knowledge of the CMake builtin defaults so they can be replaced.
CMake 3.15 and above prefer to leave out warning flags from the value of CMAKE_<LANG>_FLAGS by default.
Along with this fix, CMake introduced policy CMP0092, which allows you to switch back to the OLD behavior (adding the warning flags by default) if necessary.

Whats the proper way to link Boost with CMake and Visual Studio in Windows?

I am trying to generate some Boost 1.58 libraries that I need (chrono, regex and thread) for Visual Studio 2012 and link the libraries with CMake. I have real problems for CMake and Visual Studio to find or link the libs, depending on the configuration I set.
I am finally using the following configuration:
bjam.exe --link=static --threading multi --variant=debug stage
But this doesn't seem to generate static libs.
How should I generate the libs and search them with CMake in order for Visual Studio to link them properly?
I finally came up with the solution and I think it is detailed enough to become a generic answer.
Visual Studio searches for dynamic libraries so we need to compile Boost libraries as shared, multithreaded, debug and release, and runtime-link shared. In windows using bjam.exe all commands have the prefix "--" except link, so the right way to build the libraries is:
bjam.exe link=shared --threading=multi --variant=debug --variant=release --with-chrono --with-regex --with-thread stage
This will generate the libs and DLLs in the folder Boost/stage/lib, so we need to set an environment variable Boost_LIBRARY_DIR C:/Boost/stage/lib, for example.
There are more options that may come in hand:
runtime-link = shared/static
toolset= msvc-11.0
The libraries will have a name like this for release:
boost_chrono-vc110-mt-1_58.lib
boost_chrono-vc110-mt-1_58.dll
And for debug:
boost_chrono-vc110-mt-gd-1_58.lib
boost_chrono-vc110-mt-gd-1_58.dll
In order for CMake to link them properly we need to write the following in the CMakeLists.txt:
add_definitions( -DBOOST_ALL_DYN_LINK ) //If not VS will give linking errors of redefinitions
set(Boost_USE_STATIC_LIBS OFF )
set(Boost_USE_MULTITHREADED ON)
set(Boost_USE_STATIC_RUNTIME OFF)
find_package(Boost COMPONENTS thread chrono regex REQUIRED )
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
TARGET_LINK_LIBRARIES( ${PROJ_NAME} ${Boost_LIBRARIES} )
bjam.exe --link=static --threading multi --variant=debug stage
But this doesn't seem to generate static libs.
Building the special stage target places Boost library binaries in the stage\lib\ subdirectory of the Boost tree.
More about building Boost on Windows here
CMake:
SET (CMAKE_BUILD_TYPE Debug) # in order to link with boost debug libs you may need to set that to build your program in debug mode (or do that from command line)
FIND_PACKAGE (Boost 1.58 COMPONENTS "chrono" "regex" "thread" REQUIRED)
#ADD_DEFINITIONS(-DBOOST_ALL_DYN_LINK) # make sure you don't have this as it will try to link with boost .dll's
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
LINK_DIRECTORIES(${Boost_LIBRARY_DIRS})
TARGET_LINK_LIBRARIES(${EXE_OR_LIB_NAME} ${Boost_LIBRARIES})

Reusing custom makefile for static library with cmake

I guess this would be a generic question on including libraries with existing makefiles within cmake; but here's my context -
I'm trying to include scintilla in another CMake project, and I have the following problem:
On Linux, scintilla has a makefile in (say) the ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/gtk directory; if you run make in that directory (as usual), you get a ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/bin/scintilla.a file - which (I guess) is the static library.
Now, if I'd try to use cmake's ADD_LIBRARY, I'd have to manually specify the sources of scintilla within cmake - and I'd rather not mess with that, given I already have a makefile. So, I'd rather call the usual scintilla make - and then instruct CMAKE to somehow refer to the resulting scintilla.a. (I guess that this then would not ensure cross-platform compatibility - but note that currently cross-platform is not an issue for me; I'd just like to build scintilla as part of this project that already uses cmake, only within Linux)
So, I've tried a bit with this:
ADD_CUSTOM_COMMAND(
OUTPUT scintilla.a
COMMAND ${CMAKE_MAKE_PROGRAM}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/gtk
COMMENT "Original scintilla makefile target" )
... but then, add_custom_command adds a "target with no output"; so I'm trying several approach to build upon that, all of which fail (errors given as comment):
ADD_CUSTOM_TARGET(scintilla STATIC DEPENDS scintilla.a) # Target "scintilla" of type UTILITY may not be linked into another target.
ADD_LIBRARY(scintilla STATIC DEPENDS scintilla.a) # Cannot find source file "DEPENDS".
ADD_LIBRARY(scintilla STATIC) # You have called ADD_LIBRARY for library scintilla without any source files.
ADD_DEPENDENCIES(scintilla scintilla.a)
I'm obviously quote a noob with cmake - so, is it possible at all to have cmake run a pre-existing makefile, and "capture" its output library file, such that other components of the cmake project can link against it?
Many thanks for any answers,
Cheers!
EDIT: possible duplicate: CMake: how do i depend on output from a custom target? - Stack Overflow - however, here the breakage seems to be due to the need to specifically have a library that the rest of the cmake project would recognize...
Another related: cmake - adding a custom command with the file name as a target - Stack Overflow; however, it specifically builds an executable from source files (which I wanted to avoid)..
You could also use imported targets and a custom target like this:
# set the output destination
set(SCINTILLA_LIBRARY ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/gtk/scintilla.a)
# create a custom target called build_scintilla that is part of ALL
# and will run each time you type make
add_custom_target(build_scintilla ALL
COMMAND ${CMAKE_MAKE_PROGRAM}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/gtk
COMMENT "Original scintilla makefile target")
# now create an imported static target
add_library(scintilla STATIC IMPORTED)
# Import target "scintilla" for configuration ""
set_property(TARGET scintilla APPEND PROPERTY IMPORTED_CONFIGURATIONS NOCONFIG)
set_target_properties(scintilla PROPERTIES
IMPORTED_LOCATION_NOCONFIG "${SCINTILLA_LIBRARY}")
# now you can use scintilla as if it were a regular cmake built target in your project
add_dependencies(scintilla build_scintilla)
add_executable(foo foo.c)
target_link_libraries(foo scintilla)
# note, this will only work on linux/unix platforms, also it does building
# in the source tree which is also sort of bad style and keeps out of source
# builds from working.
OK, I think I have it somewhat; basically, in the CMakeLists.txt that build scintilla, I used this only:
ADD_CUSTOM_TARGET(
scintilla.a ALL
COMMAND ${CMAKE_MAKE_PROGRAM}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/scintilla/gtk
COMMENT "Original scintilla makefile target" )
... and then, the slightly more complicated part, was to find the correct cmake file elsewhere in the project, where the ${PROJECT_NAME} was defined - so as to add a dependency:
ADD_DEPENDENCIES(${PROJECT_NAME} scintilla.a)
... and finally, the library needs to be linked.
Note that in the commands heretofore, the scintilla.a is merely a name/label/identifier/string (so it could be anything else, like scintilla--a or something); but for linking - the full path to the actual `scintilla.a file is needed (which in this project ends up in a variable ${SCINTILLA_LIBRARY}). In this project, the linking basically occurs through a form of a
list(APPEND PROJ_LIBRARIES ${SCINTILLA_LIBRARY} )
... and I don't really know how cmake handles the actual linking afterwards (but it seems to work)
For consistency, I tried to use ${SCINTILLA_LIBRARY} instead of scintilla.a as identifier in the ADD_CUSTOM_TARGET, but got error: "Target names may not contain a slash. Use ADD_CUSTOM_COMMAND to generate files". So probably this could be solved smarter/more correct with ADD_CUSTOM_COMMAND - however, I read that it "defines a new command that can be executed during the build process. The outputs named should be listed as source files in the target for which they are to be generated."... And by now I'm totally confused so as to what is a file, what is a label, and what is a target - so I think I'll leave at this (and not fix it if it ain't broken :) )
Well, it'd still be nice to know a more correct way to do this eventually,
Cheers!

Problems with CMAKE vars

I'm using CMAKE to generate VS2008 SLN/VCPROJ files but a few simple things don't appear to work:
1)This works: INCLUDE_DIRECTORIES ($ENV{MCS_OGRE_HOME}/OgreMain/include)
But this doesn't, my VC++ additional include dirs gets totally screwed up when I do this, brackets and all kinds floating around:
SET (OGRE_PATH $ENV{OGRE_HOME}/OgreMain)
INCLUDE_DIRECTORIES (${OGRE_PATH}/include)
2)This works: target_link_libraries( debug $ENV{OGRE_HOME}/lib/OgreMainStatic_d.lib )
But this doesn't, the library path isn't shown under the library paths in VC++:
LINK_DIRECTORIES($ENV{OGRE_HOME}/lib/)
target_link_libraries( debug OgreMainStatic_d.lib )
I figure it must be something simple?
Rather than:
set(OGRE_PATH $ENV{OGRE_HOME}/OgreMain)
Use:
string(REPLACE "\\" "/" OGRE_PATH "$ENV{OGRE_HOME}/OgreMain")
CMake uses all "/" for path separators on all platforms.
Also, it's recommended to use full path names (with "/" separators) as library arguments to target_link_libraries rather than specifying link_directories. CMake then takes the whole set of libraries linked to and figures out the right order to pass linker flags on all platforms.
One more comment: looks like you have a library or an executable named "debug" from your call to target_link_libraries. Is that true? Or are you missing the first argument in the question posted here?
Should be something like:
target_link_libraries(mylib
debug /path/to/DebugLib.lib
optimized /path/to/ReleaseLib.lib)

Resources