273

I'm currently constructing a project with a plugin structure. I'm using CMake to compile the project. The plugins are compiled in separate directories. My problem is that CMake compiles and saves the binaries and plugins, dynamic libraries, in the directory structure of the source. How do I make CMake save the files in something like a ./bin directory?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Martin Kristiansen
  • 9,875
  • 10
  • 51
  • 83
  • 2
    You should not override CMake's build directory layout. Instead, use the [install()](https://cmake.org/cmake/help/latest/command/install.html) command and `cmake --install`. It will automatically copy executables to a `bin` subdirectory by default. – alexchandel Mar 01 '23 at 17:34
  • @alexchandel lol -- this was 11 year ago :) I love that you found it, and if thats true, it's a great answer :) – Martin Kristiansen Mar 01 '23 at 23:54

10 Answers10

413

As in Oleg's answer, I believe the correct variable to set is CMAKE_RUNTIME_OUTPUT_DIRECTORY. We use the following in our root CMakeLists.txt:

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)

You can also specify the output directories on a per-target basis:

set_target_properties( targets...
    PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
)

In both cases you can append _[CONFIG] to the variable/property name to make the output directory apply to a specific configuration (the standard values for configuration are DEBUG, RELEASE, MINSIZEREL and RELWITHDEBINFO).

starball
  • 20,030
  • 7
  • 43
  • 238
Adam Bowen
  • 10,820
  • 6
  • 36
  • 41
  • 8
    You can also override this on a per-target basis by setting the RUNTIME_OUTPUT_DIRECTORY target property. See documentation here: http://cmake.org/cmake/help/cmake-2-8-docs.html#prop_tgt:RUNTIME_OUTPUT_DIRECTORY – DLRdave Jul 07 '11 at 11:05
  • 5
    DLRdave's link is dead. Try http://cmake.org/cmake/help/v2.8.8/cmake.html#prop_tgt:RUNTIME_OUTPUT_DIRECTORY – Nicu Stiurca Jun 27 '12 at 22:20
  • How to make it apply to all configurations at once? – Emil Laine May 23 '15 at 21:24
  • The first three commands should apply to all configurations (specifically setting CMAKE_RUNTIME_OUTPUT_DIRECTORY). You would only set CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG (for example) if you wanted a different directory for debug output. The exact behaviour depends on the generator/toolchain you are using (for example Visual Studio project files include all configurations in one build tree, whilst the makefile generator will only generate makefiles for one build configuration). – Adam Bowen May 23 '15 at 22:49
  • 1
    What is the purpose of setting `CMAKE_ARCHIVE_OUTPUT_DIRECTORY`, considering that the command `install(TARGETS )` still complains about "given no RUNTIME DESTINATION for executable target"? This variable supposedly provides a default value, therefore the `install` command should not complain about the absence of a `RUNTIME DESTINATION`. – thiagowfx Jan 18 '17 at 16:48
  • 2
    `CMAKE_ARCHIVE_OUTPUT_DIRECTORY` sets where static (archive) libraries (.a files on Linux) will be built. It doesn't affect where `install` puts files. – Adam Bowen Jan 18 '17 at 16:53
  • The problem is CMake isn't consistent. For example, `dll` is considered `RUN_TIME_OUTPUT` for CMake. Is there a list which says what is what in CMake? – Royi Apr 07 '18 at 13:17
  • @Royi everything is documented. If we learned anything at all about programming, is that Windows is always a [special](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#runtime-output-artifacts) child. I assume that's because `dll` in general are bundled together and there's no set way to just "install to the system" unlike on proper OS'es and so CMake devs decided to not bother separating them, as there's almost never a reason to do that. – Kaihaku Sep 14 '21 at 12:31
  • 1
    take notice, you should put CMAKE_*** directives before adding the targets. – Possum Gallo Nov 29 '22 at 09:04
39

Use set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "/some/full/path/to/bin")

Guy Avraham
  • 3,482
  • 3
  • 38
  • 50
ovk
  • 2,318
  • 1
  • 23
  • 30
  • 11
    Use the full path name to the directory as the variable value, and do not put a trailing "/" in the value... as in Adam Bowen's answer. – DLRdave Jul 07 '11 at 10:53
  • 5
    Why do you need to add the full path? It seems like an annoyance when you move your project... – Scorb Mar 13 '18 at 01:19
  • 1
    maybe change the path "/some/full/path/to/bin" to something relative to the root CMakeLists.txt which will have its path set in ${CMAKE_SOURCE_DIR} – hamaney Dec 20 '20 at 20:32
  • Does exactly what I want. You might want to use some variable like `${PROJECT_SOURCE_DIR}/some/path` or `${CMAKE_BINARY_DIR}/some/path.` – Vasantha Ganesh Mar 29 '23 at 14:42
9

Use the EXECUTABLE_OUTPUT_PATH CMake variable to set the needed path. For details, refer to the online CMake documentation:

CMake 2.8.8 Documentation

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
gtikok
  • 1,119
  • 8
  • 18
7

As to me I am using cmake 3.5, the below(set variable) does not work:

set(
      ARCHIVE_OUTPUT_DIRECTORY "/home/xy/cmake_practice/lib/"
      LIBRARY_OUTPUT_DIRECTORY "/home/xy/cmake_practice/lib/"
      RUNTIME_OUTPUT_DIRECTORY "/home/xy/cmake_practice/bin/"
)

but this works(set set_target_properties):

set_target_properties(demo5
    PROPERTIES
    ARCHIVE_OUTPUT_DIRECTORY "/home/xy/cmake_practice/lib/"
    LIBRARY_OUTPUT_DIRECTORY "/home/xy/cmake_practice/lib/"
    RUNTIME_OUTPUT_DIRECTORY "/home/xy/cmake_practice/bin/"
)
Jayhello
  • 5,931
  • 3
  • 49
  • 56
  • 8
    I am using Adam's answer with set (CMAKE_... and it works, but only when you do it before adding libraries, executables etc. I think it's an important note for beginners like me. – ashrasmun Jun 15 '19 at 07:51
  • 3
    Wow. @ashrasmun saved me from going insane after a few hours. Absolutely nothing was working until coming to the realization that the order of these commands is very relevant. – arthropod Dec 28 '19 at 00:06
  • CMake version 3.19, this worked: set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "/some/full/path/to/bin"). Also you can specify path relative to the current directory (directory from which the cmake command is being executed). – victorm1710 Feb 24 '21 at 21:09
5
$ cat CMakeLists.txt
project (hello)
set(EXECUTABLE_OUTPUT_PATH "bin")
add_executable (hello hello.c)
mcandre
  • 22,868
  • 20
  • 88
  • 147
2

Use this line config:

set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/build/)
place your any CMakeLists.txt project.

This ${PROJECT_SOURCE_DIR} is your current source directory where project place .
and if wander why is ${EXECUTABLE_OUTPUT_PATH} check this file CMakeCache.txt then search the key word output path, all the variables define here, it would give a full explanation of the project all setting.

user438383
  • 5,716
  • 8
  • 28
  • 43
jdir.s
  • 97
  • 8
  • This will force the executable to be build in the project working directory, which is counter to what the OP is trying to do. It's generally a bad idea. (What if you want to build two different configurations?) Also, `EXECUTABLE_OUTPUT_PATH` is superseded by `RUNTIME_OUTPUT_DIRECTORY`. – John McFarlane Feb 12 '23 at 09:35
2

To add on to this:

If you're using CMAKE to generate a Visual Studio solution, and you want Visual Studio to output compiled files into /bin, Peter's answer needs to be modified a bit:

# set output directories for all builds (Debug, Release, etc.)
foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
    string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG )
    set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_SOURCE_DIR}/lib )
    set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_SOURCE_DIR}/lib )
    set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_SOURCE_DIR}/bin )
endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES )
serg06
  • 2,027
  • 1
  • 18
  • 26
2

One more refinement to serg06's answer:

To force the three paths to be used as-is with all generators and for all build configurations, you can add an empty generator expression as in the following:

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "$<0:>${CMAKE_BINARY_DIR}/bin") # .exe and .dll
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "$<0:>${CMAKE_BINARY_DIR}/lib") # .so and .dylib
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "$<0:>${CMAKE_BINARY_DIR}/lib") # .lib and .a

That has the side-effect of forcing the Visual Studio generator in particular to use the specified path as-is, instead of appending a configuration-specific subdirectory, with no need for a foreach loop.

BTJ
  • 188
  • 2
  • 5
1

Be careful about changing the OUTPUT_DIRECTORY like the answers above describe. It's not an ideal solution since it can make your CMake project less friendly to add_subdirectory users.

I'm currently constructing a project with a plugin structure. I'm using CMake to compile the project. The plugins are compiled in separate directories. My problem is that CMake compiles and saves the binaries and plugins, dynamic libraries, in the directory structure of the source.

Sounds like your real issue is trying to load dlls.

CMake 3.21 added functionality for this exact situation.

$<TARGET_RUNTIME_DLLS:tgt> New in version 3.21.

This generator expression can be used to copy all of the DLLs that a target depends on into its output directory in a POST_BUILD custom command using the cmake -E copy -t command. For example:

find_package(foo CONFIG REQUIRED) # package generated by install(EXPORT)

add_executable(exe main.c)
target_link_libraries(exe PRIVATE foo::foo foo::bar)
add_custom_command(TARGET exe POST_BUILD
    COMMAND ${CMAKE_COMMAND} -E copy -t $<TARGET_FILE_DIR:exe> $<TARGET_RUNTIME_DLLS:exe>
    COMMAND_EXPAND_LISTS
)

Link to official documentation:

https://cmake.org/cmake/help/latest/manual/cmake-generator-expressions.7.html#genex:TARGET_RUNTIME_DLLS

Fundamentally this is a Windows issue CMake tries to provide a nice solution for since the MSVC compiler doesn't have RPATH support. Which makes this a trivial problem on almost all systems except for Windows.

jpr42
  • 718
  • 3
  • 14
-1
cat CMakeLists.txt
project (hello)
set(CMAKE_BINARY_DIR "/bin")
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
add_executable (hello hello.c)
Paul Floyd
  • 5,530
  • 5
  • 29
  • 43
Meet Modia
  • 15
  • 1