1

I am building a multi-platform library and recently made a change in the source files.

Basically, I now got:

\sources
|----\common
     |---- tcp_socket.cpp
|----\windows
     |---- tcp_socket.cpp
|----\unix
     |---- tcp_socket.cpp

While it compiles fine on mac/linux and some VC++ versions, some of the users of my library encounter the stupid MSVC error:

MSB8027 Two or more files with the name of tcp_socket.cpp will produce outputs to the same location. This can lead to an incorrect build result. The files involved are ..\Classes\socket\tacopie\network\common\tcp_socket.cpp, ..\Classes\socket\tacopie\network\unix\tcp_socket.cpp, ..\Classes\socket\tacopie\network\windows\tcp_socket.cpp.   test C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V140\Microsoft.CppBuild.targets  936

The solution I keep seeing over and over again is like the one reported here: VisualStudio project with multiple sourcefiles of the same name? Basically, changing the Object Filename property of Output File configuration for the project properties in VC++ from $(IntDir) to $(IntDir)%(RelativeDir).

That sounds like a working solution, but I'd like to set it up directly from the CMakelist, otherwise, the users of my library would have to do this trick by themselves.

Is there any way to achieve that with CMake?

Edit: below is the cmakelist

###
# config
###
cmake_minimum_required(VERSION 2.8.7)
set(CMAKE_MACOSX_RPATH 1)
include(${CMAKE_ROOT}/Modules/ExternalProject.cmake)


###
# verbose make
###
# set(CMAKE_VERBOSE_MAKEFILE TRUE)


###
# project
###
set(PROJECT tacopie)
project(${PROJECT} CXX)


###
# compilation options
###
IF (WIN32)
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /O2 /bigobj")

  # was causing conflics with gtest build
  string(REPLACE "/RTC1" "" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})

  IF ("${MSVC_RUNTIME_LIBRARY_CONFIG}" STREQUAL "")
    set(MSVC_RUNTIME_LIBRARY_CONFIG "/MT")
  ENDIF()

  foreach (flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE)
    IF ("${MSVC_RUNTIME_LIBRARY_CONFIG}" STREQUAL "/MT")
      string(REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
    ELSEIF ("${MSVC_RUNTIME_LIBRARY_CONFIG}" STREQUAL "/MD")
      string(REPLACE "/MT" "/MD" ${flag_var} "${${flag_var}}")
    ELSE ()
      string(REPLACE "/MD" "${MSVC_RUNTIME_LIBRARY_CONFIG}" ${flag_var} "${${flag_var}}")
      string(REPLACE "/MT" "${MSVC_RUNTIME_LIBRARY_CONFIG}" ${flag_var} "${${flag_var}}")
    ENDIF()
  endforeach()

  add_definitions(-D_UNICODE)
  add_definitions(-DUNICODE)
  add_definitions(-DWIN32_LEAN_AND_MEAN)
ELSE ()
  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -W -Wall -Wextra -O3")
ENDIF (WIN32)


###
# variables
###
set(DEPS_INCLUDES ${PROJECT_SOURCE_DIR}/deps/include)
set(DEPS_LIBRARIES ${PROJECT_SOURCE_DIR}/deps/lib)
set(TACOPIE_INCLUDES ${PROJECT_SOURCE_DIR}/includes)


###
# includes
###
include_directories(${TACOPIE_INCLUDES})

###
# sources
###
set(SRC_DIRS "sources" "sources/network" "sources/network/common" "sources/utils" "includes/tacopie" "includes/tacopie/network" "includes/tacopie/utils")

IF (WIN32)
  set(SRC_DIRS ${SRC_DIRS} "sources/network/windows")
ELSE ()
  set(SRC_DIRS ${SRC_DIRS} "sources/network/unix")
ENDIF (WIN32)

foreach(dir ${SRC_DIRS})
  # get directory sources and headers
  file(GLOB s_${dir} "${dir}/*.cpp")
  file(GLOB h_${dir} "${dir}/*.hpp")
  file(GLOB i_${dir} "${dir}/*.ipp")

  # set sources
  set(SOURCES ${SOURCES} ${s_${dir}} ${h_${dir}} ${i_${dir}})
endforeach()


###
# outputs
###
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)


###
# executable
###
add_library(${PROJECT} STATIC ${SOURCES})

IF (WIN32)
   set_target_properties(${PROJECT}
                         PROPERTIES COMPILE_PDB_NAME ${PROJECT}
                         COMPILE_PDB_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
ENDIF (WIN32)

IF (WIN32)
  target_link_libraries(${PROJECT} ws2_32)
ELSE ()
  target_link_libraries(${PROJECT} pthread)
ENDIF (WIN32)

# __TACOPIE_LOGGING_ENABLED
IF (LOGGING_ENABLED)
  set_target_properties(${PROJECT} PROPERTIES COMPILE_DEFINITIONS "__TACOPIE_LOGGING_ENABLED=${LOGGING_ENABLED}")
ENDIF (LOGGING_ENABLED)

# __TACOPIE_CONNECTION_QUEUE_SIZE
IF (CONNECTION_QUEUE_SIZE)
  set_target_properties(${PROJECT} PROPERTIES COMPILE_DEFINITIONS "__TACOPIE_CONNECTION_QUEUE_SIZE=${CONNECTION_QUEUE_SIZE}")
ENDIF (CONNECTION_QUEUE_SIZE)

#__TACOPIE_IO_SERVICE_NB_WORKERS
IF (IO_SERVICE_NB_WORKERS)
  set_target_properties(${PROJECT} PROPERTIES COMPILE_DEFINITIONS "__TACOPIE_IO_SERVICE_NB_WORKERS=${IO_SERVICE_NB_WORKERS}")
ENDIF(IO_SERVICE_NB_WORKERS)

#__TACOPIE_TIMEOUT
IF (SELECT_TIMEOUT)
  set_target_properties(${PROJECT} PROPERTIES COMPILE_DEFINITIONS "__TACOPIE_TIMEOUT=${SELECT_TIMEOUT}")
ENDIF(SELECT_TIMEOUT)


###
# install
###
# ensure lib and bin directories exist
install(DIRECTORY DESTINATION ${CMAKE_BINARY_DIR}/lib/)
install(DIRECTORY DESTINATION ${CMAKE_BINARY_DIR}/bin/)
# install tacopie
install (DIRECTORY ${CMAKE_BINARY_DIR}/lib/ DESTINATION lib USE_SOURCE_PERMISSIONS)
install (DIRECTORY ${CMAKE_BINARY_DIR}/bin/ DESTINATION bin USE_SOURCE_PERMISSIONS)
install (DIRECTORY ${TACOPIE_INCLUDES}/ DESTINATION include USE_SOURCE_PERMISSIONS)


###
# examples
###
IF (BUILD_EXAMPLES)
  add_subdirectory(examples)
ENDIF(BUILD_EXAMPLES)


###
# tests
###
IF (BUILD_TESTS)
  add_subdirectory(tests)
  ExternalProject_Add("googletest"
                      GIT_REPOSITORY "https://github.com/google/googletest.git"
                      CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${PROJECT_SOURCE_DIR}/deps")
ENDIF(BUILD_TESTS)
Simon Ninon
  • 2,371
  • 26
  • 43
  • Are you adding both the windows and unix tcp_socket.cpp files to your target regardless of what platform you're building on? If so, stop. Just add the correct source file to the project based on what platform you are on – xaxxon Sep 26 '17 at 08:49
  • I'm just adding the correct file. The issue is due to the common file for both platform and the platform specific file as the error mentioned. – Simon Ninon Sep 26 '17 at 08:51
  • Can you please show your `CMakeLists.txt` code? Then we could suggest a CMake based solution to this problem. – Florian Sep 26 '17 at 08:58
  • edited my questions to add it :) – Simon Ninon Sep 26 '17 at 09:04
  • do you have a CMakeLists.txt in both command and windows? – xaxxon Sep 26 '17 at 09:16
  • no, sources are globbed by using GLOB somedir *.cpp for each subfolder of the source directory. – Simon Ninon Sep 26 '17 at 09:27
  • Why not rename common\tcp_socket to common\common_tcp_socket or something similar? – André Sep 26 '17 at 10:36
  • that's what I did for now, but I'm not a big fan (I feel it is redundant to have unix/unix_tcp_socket, and it is a mess to have everything in same directory). So I'm mostly looking for a clean way to handle that case with CMake, but kind of losing hope :/ Dealing with MSVC is always so tiring. – Simon Ninon Sep 26 '17 at 10:53
  • One option is to build the subdirs as their own static library that is consumed by your existing target. – legalize Sep 28 '17 at 22:44

0 Answers0