imgui
imgui copied to clipboard
Add CMake configuration
Supersedes #1713. This is a much simpler configuration for use with CMake projects.
Provided here as suggested in https://github.com/ocornut/imgui/pull/1713#issuecomment-586867302.
Platforms
- [ ] MacOS
- [ ] iOS
- [ ] Linux
- [ ] Windows
- [ ] Emscripten
General TODO's
- [ ] Move c++11 build flags into appropriate examples (instead of at the root, since ImGui is specified to be buildable without c++11 support)
- [ ] Package iOS/macOS app examples so they can be tested directly
- [ ] Add header files to targets so they show up in generated project files (for applicable generators)
Examples
- [ ]
example_allegro5
- [x]
example_apple_metal
- [x]
example_apple_opengl2
- [ ]
example_emscripten
- [x]
example_glfw_metal
- [x]
example_glfw_opengl2
- [x]
example_glfw_opengl3
- [ ]
example_glfw_vulkan
- [x]
example_glut_opengl2
- [x]
example_null
- [ ]
example_sdl_directx11
- [x]
example_sdl_metal
- [x]
example_sdl_opengl2
- [x]
example_sdl_opengl3
- [ ]
example_sdl_vulkan
- [x]
example_win32_directx10
- [x]
example_win32_directx11
- [x]
example_win32_directx12
- [x]
example_win32_directx9
Implementations
- [ ] imgui_impl_allegro5
- [x] imgui_impl_dx10
- [x] imgui_impl_dx11
- [x] imgui_impl_dx12
- [x] imgui_impl_dx9
- [x] imgui_impl_glfw
- [x] imgui_impl_glut
- [x] imgui_impl_metal
- [x] imgui_impl_opengl2
- [x] imgui_impl_opengl3
- [x] imgui_impl_osx
- [x] imgui_impl_sdl
- [ ] imgui_impl_vulkan
- [x] imgui_impl_win32
Let me know if I'm missing anything.
Any guidance on how to test Marmalade apps would be appreciated. I'd be happy to add the configuration for them.
Hey i like clarity of CMake code in this PR. Great job :+1:
I have a few commends:
imgui-sdl
vs imgui_example_sdl_opengl3
naming style. Any particular reason you mix -
with _
?
I think it would be very convenient if we could have all of cmake scripts in one file. I know this is not exactly conventional in CMake projects. Reason i am suggesting it is because Dear ImGui is a multi-buildsystem project and CMake support would be an addon instead of a main build system. Example targets could be created by one-liner if we made a macro for it. Defining most examples is almost same.
Third party dependencies could use some touching up. For example if imgui-sdl
was INTERFACE
library we could essentially omit it from visible targets and avoid polluting user's targets list. Libraries, includes and even source files can be added to a target using INTERFACE
visibility to achieve exact same result. Note that it is important to allow users to link their own SDL/GLFW/etc in-tree dependencies.
imgui-sdl
should use pkg-config on MacOS. Also newer CMake creates SDL2::SDL2
imported target which users are supposed to link. Here is example of how i handle it:
if (NOT DEFINED IMGUI_SDL_TARGET)
find_package(SDL2 QUIET)
if (TARGET SDL2::SDL2)
# Some platforms (Linux) have SDL target properly exported as CMake target.
set (IMGUI_SDL_TARGET SDL2::SDL2)
elseif (SDL2_FOUND)
# Platforms that do not export target but use old CMake conventions can be handled this way.
add_library(SDL2::SDL2 INTERFACE IMPORTED)
target_link_libraries(SDL2::SDL2 INTERFACE ${SDL2_LIBRARIES})
target_include_directories(SDL2::SDL2 INTERFACE ${SDL2_INCLUDE_DIRS})
set (IMGUI_SDL_TARGET SDL2::SDL2)
elseif (NOT "$ENV{SDL2_DIR}" STREQUAL "")
# On windows we may set SDL2_DIR environment variable and link to binary SDL distribution.
add_library(SDL2::SDL2 INTERFACE IMPORTED)
set_target_properties(SDL2::SDL2 PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES $ENV{SDL2_DIR}/include
INTERFACE_LINK_LIBRARIES "$ENV{SDL2_DIR}/lib/${IMGUI_PLATFORM_ARCH}/SDL2.lib;$ENV{SDL2_DIR}/lib/${IMGUI_PLATFORM_ARCH}/SDL2main.lib"
)
set (IMGUI_SDL_TARGET SDL2::SDL2)
add_custom_target(CopySDL ALL COMMAND ${CMAKE_COMMAND} -E copy
"$ENV{SDL2_DIR}/lib/${IMGUI_PLATFORM_ARCH}/SDL2.dll" "${IMGUI_OUTPUT_DIR}/$<CONFIG>/SDL2.dll")
add_dependencies(${IMGUI_SDL_TARGET} CopySDL)
elseif (PkgConfig_FOUND)
# Rest of the platforms (like MacOS) can consume SDL via pkg-config.
pkg_check_modules(SDL2 QUIET IMPORTED_TARGET sdl2)
if (SDL2_FOUND)
set (IMGUI_SDL_TARGET PkgConfig::sdl2)
endif ()
endif ()
endif ()
This is not perfect, but could serve as a starting point. CopySDL
is especially bad, but i failed to get CMake copy a DLL even though it is supposed to be able to.
My GLFW bit:
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../glfw/CMakeLists.txt)
# When parent directory contains GLFW source code - we can build it directly.
set (GLFW_STANDALONE OFF)
set (GLFW_INSTALL OFF)
set (GLFW_BUILD_DOCS OFF)
add_subdirectory (${CMAKE_CURRENT_SOURCE_DIR}/../glfw ${CMAKE_CURRENT_BINARY_DIR}/glfw)
set (IMGUI_GLFW_TARGET glfw)
elseif (MSVC)
# We ship compiled libraries in our repository for Visual Studio.
add_library(glfw INTERFACE IMPORTED)
target_link_libraries(glfw INTERFACE libs/glfw/lib-vc2010-${IMGUI_PLATFORM_BITS}/glfw3.lib)
target_include_directories(glfw INTERFACE libs/glfw/include)
set (IMGUI_GLFW_TARGET glfw)
elseif (PkgConfig_FOUND)
pkg_check_modules(GLFW QUIET IMPORTED_TARGET glfw3)
if (GLFW_FOUND)
set (IMGUI_GLFW_TARGET PkgConfig::glfw)
endif ()
endif ()
Any guidance on how to test Marmalade apps would be appreciated. I'd be happy to add the configuration for them.
You can ignore this, I am going to scrap that backend and move it elsewhere eventually.
Hey @rokups, thanks for the feedback!
Any particular reason you mix - with _?
Yes - using the -
in library names is typical of target names in CMake, namely libraries (sometimes you get weird variances, e.g. I've seen static library targets denoted with a _a
, as is the case with libuv). I use _
in the executable names because that doubles as the output executable's name (e.g. imgui_example_sdl_opengl3.exe
) and they won't be used by any consuming application.
I think it would be very convenient if we could have all of cmake scripts in one file.
I'll defer to @ocornut here, but I will say this: it is indeed very unconventional, and it's going to hurt maintainability in the long-term. I highly recommend against it.
we could essentially omit it from visible targets
I didn't know INTERFACE
libraries did this - how are they supposed to be consumed, then? Can you find a link that talks about INTERFACE
libraries not being visible? As-is, they are object libraries, meaning we can control the build flags that go into the implementations but they are not linked together or archived into a library file (and are thus just included as object files in the consuming application).
Note that it is important to allow users to link their own SDL/GLFW/etc in-tree dependencies.
Definitely; this is how I intend to use ImGui in my projects as well. I still need to test, but I've written the configuration with this in mind, and I believe the current configuration allows for this. If not, NOT TARGET
clauses can be trivially added, or even option()
s (which is pretty typical - you see it a lot with SSL-enabled libraries, for example).
imgui-sdl should use pkg-config on MacOS. Also newer CMake creates SDL2::SDL2 imported target which users are supposed to link. Here is example of how i handle it:
I'll give it a shot, thanks :)
You can ignore this
Sounds good; what about allegro? I'm not familiar with that either.
@rokups your glfw pkgconfig code seems to fail for me:
CMake Error at examples/example_glfw_opengl3/CMakeLists.txt:2 (add_executable):
Target "imgui_example_glfw_opengl3" links to target "PkgConfig::glfw3" but
the target was not found. Perhaps a find_package() call is missing for an
IMPORTED target, or an ALIAS target is missing?
Can you find a link that talks INTERFACE libraries not being visible?
Imported library description does not mention this property. I guess invisibility is a byproduct of library not producing any output. And they arent object libraries as object libraries are ones that compile source files but do not link them into libraries/exes. They just inject extra includes/libs/flags to linking target. But we can exploit them to also inject source files to linking targets by using target_sources()
.
@rokups your glfw pkgconfig code seems to fail for me
Could maybe CMake version being rather old? See https://cmake.org/cmake/help/v3.17/module/FindPkgConfig.html?highlight=pkg%20config#module:FindPkgConfig for your version of CMake. PkgConfig::
prefix is not something that existed from 3.1.
I guess invisibility is a byproduct of library not producing any output
This seems strange. Targets shouldn't be able to conflict - CMake wouldn't know what to do. I think there's a missing piece of information somewhere here 😅
In your opinion, what are the pros/cons of using import libraries vs. object libraries?
Could maybe CMake version being rather old?
$ cmake --version
cmake version 3.16.2
Hello @Qix-, add Emscripten
to platforms (example_emscripten
). More there,
@podsvirov I didn't add it since it's not an impl
. It uses SDL and opengl3 under the hood - it's just a compiler change.
EDIT: nevermind, I see what you mean. Added :)
@Qix-, any efforts to export your configuration for others and install examples?
PS: my acount is @podsvirov :-). Dear @podgorskiy, sorry for noise.
Whoops, sorry about that. Don't know why github did that. 😅 (EDIT: Oh I see he's also active around here; yes, sorry for the noise indeed!)
What do you mean by exporting configuration? As far as installation, I don't know that examples really need to have install targets.
Yes, we can simply built examples, but then we simply build only examples... Have you experience to build and export CMake package for others?
I don't understand what you mean by "package". Packaging what, and for whom? ImGui examples aren't going to be used by anyone outside the project, so there's no point in having an install target for them. What's the use-case? I'm pretty reluctant on adding anything that doesn't need to be added.
What is holding back the vulkan stuff? I see the cmake files in the commit.
@Cazadorro I only have a mac machine and (correct me if I'm wrong) ImGui doesn't have a MoltenVK sample (I've never worked with moltenvk personally).
Further, you can't test Vulkan in virtual machines yet (at least, VMWare doesn't support it). Just compilation, but that doesn't tell me if it actually runs or not.
I haven't used moltenvk, but theoretically it should be exposed the same way as vulkan, so I don't think it would require a code change to support. Do you need people to run things for you? I've got vulkan on my machines, and have gotten imgui to work in vulkan based off of the examples and implementations.
I can poke around a bit and try a cmake config for it, push it here, and have windows/linux folks try it ^^
Some things I was thinking about, will there be options to include things like the c++ extensions found in misc?
Yes. I'll be testing this branch in my engine within the next few weeks and will want some of those things personally as well. The only hang up on my end is that there isn't a self-contained bgfx implementation I'm imgui so I'll have to adapt the one I'm using to this new system instead.
At that point I'll be able to get all of misc/ stuff added as well.
Hey i worked off of your ideas and came up with this: https://gist.github.com/rokups/568c4f69f25793d6c5b90fa958d5b5a4
Core moments of my implementation:
- Single file (if we are going to support multiple build systems this will be useful. We have at least premake on our radar. Meson might be a good idea too)
- Works when CMakeLists.txt is either in project root or examples dir (we will probably want to have build files in examples dir, but symlinking it to root dir and opening root dir in IDE helps CLion recognize headers as part of the project.)
- A flag to add required build options for coverage analysis
- Non-essential targets are
INTERFACE
orIMPORTED
and that does not pollute your project's target list: - Not complete still. Missing stuff:
- Emscripten build (simple to add, would need to ship a toolchain file though)
- example_apple_metal is still broken when building with makefile generator (not trivial to get working it seems, or im just bad at apple stuff)
- Opted to not use imported targets with pkg-config which fixes builds with oldest supported cmake.
- no iOS builds
- no plans to add allegro and marmalade samples
I really do like idea of imgui-{backend}
targets. It removed so much duplication from build script. Feel free to salvage whatever you find useful.
Please avoid Meson. Nothing but headaches with its dogmatic structure and the maintainer is extremely difficult to work with.
@rokups Why not just directly list the header files to get Clion to recognize them?
@Cazadorro that was my first thought. Unfortunately headers are ignored when CMakeLists.txt
includes them from parent directory. I know, does not make much sense.
@rokups wait why would you be trying to do that? That CMakeLists.txt is already at the top level what .h file are you trying to get at? Actually I'm confused now why putting it all into one file was a good thing?
@rokups wait why would you be trying to do that? That CMakeLists.txt is already at the top level what .h file are you trying to get at?
We like to keep top level directory as clean as possible so chances are build files will have to go into a subdirectory.
Actually I'm confused now why putting it all into one file was a good thing?
CMake support can be achieved in two ways:
- Migrating official project build system to CMake
- Maintaining a CMake build script while not treating it as a main build system
In case of 1. it does might sense to have separate files, but only if project is big. In case of small projects like Dear ImGui (or maybe i should say low-translation-unit-count, because this isnt a small project at all) and in case of 2. seems to me having everything in one file is just cleaner. At the moment my build script is ~500 lines and it isnt going to grow that much any more.
Also consider users that already use Dear ImGui with any other build system, or even with CMake, but have their own build scripts. They would surely prefer getting (and possibly deleting) one extra file instead of tens of extra files.
Dear ImGui has a great many users with a great many of conflicting interests. We have to try to think of them all when doing changes.
The reason why I prefer to break out CMake configuration files into smaller pieces is because fishing through hundreds of lines of a somewhat unreadable DSL (cmake's scripting language) can be a bit of a maintenance nightmare if not formatted correctly.
What's more, is that to DRY up cmake, usually people resort to functions or macros - but given how CMake's scoping works (or, more importantly, how it doesn't work) it can quickly cause over-engineered scripts to emerge, as seen in #1713.
Splitting this out into its component files makes
- adding implementations trivial
- adding examples trivial
- understanding individual pieces of the build system quick to identify, grep or grok (understand)
I don't agree with the notion of CMake being an auxilliary build system warranting it be collapsed into an equally messy configuration file that nobody will want to maintain. That kind of defeats the purpose of this PR, which was to clean up a few other CMake proposals that were otherwise hairy or over-engineered.
We like to keep top level directory as clean as possible so chances are build files will have to go into a subdirectory.
This doesn't make sense. All the CMakeLists.txt has to do is sit there. Anybody who previously used ImGui is simply not effected by the fact a CMakeLists.txt file sits at the top level directory.
CMake support can be achieved in two ways:
- Migrating official project build system to CMake
- Maintaining a CMake build script while not treating it as a main build system
In case of 1. it does might sense to have separate files, but only if project is big.
No... I've never seen this pattern before. Giant CMake files are un-maintainable. The standard practice is to have one CMakeList.txt per new created target when reasonable, no matter the size of the project it. Not splitting targets up into individual CMakeLists.txt also has consequences for pull requests. Multiple people can't fix multiple issues with CMake at the same time.
Also consider users that already use Dear ImGui with any other build system, or even with CMake, but have their own build scripts. They would surely prefer getting (and possibly deleting) one extra file instead of tens of extra files.
The fact that CMakeLists.txt exists there does not stop any one from using any other build system. And thus far only CMake has seen enough support to have major efforts underway to add support (like this current effort), so other build systems aren't terribly relevant. If people have to go in and move files around to get the build system to work, that defeats the purpose of any build system. The project would no longer be drop in and go (which imGui would be with a top level CMakeList.txt file), and now everytime I update from master I'll have to mess with files again. That isn't maintainable.
Dear ImGui has a great many users with a great many of conflicting interests. We have to try to think of them all when doing changes.
Make doesn't care about CMake. neither does NinjaMake, Bazel doesn't either. To my knowledge no non CMake based build system gives a hoot whether a CMakeList.txt exists, unless it wants to integrate, in which case a CMakeList.txt is a good thing, Even meson doesn't care, and even has support for CMake based subprojects.
Caring too much about other build systems, even if they did cause issues, is making perfect the enemy of good. CMake has the widest penetration of Meta-buildsystems in C++, it's the reason Clion decided to go with CMake as the build system they integrated. Most projects, especially large projects in C++, use CMake. It's also currently the only build-system with sufficient support to actually push up to master tomorrow if we really wanted to.
I just have some small suggestions for your top-level CMakeLists.txt .
I would recommmend removing STATIC
from the following line:
add_library (imgui STATIC imgui.cpp imgui_draw.cpp imgui_widgets.cpp ${IMGUI_DEMO_SRC} )
CMake will build the library as a static library by default and users can override this by setting the variable BUILD_SHARED_LIBS=ON
.
Setting STATIC here will override user preferences.
Furthermore I would recommend adding a alias library target for the imgui
target as it is more in line with idiomatic modern cmake and it clearly identifies it as a target to clients instead of possibly being confused as a linker flag (i.e -limgui).
add_library(imgui::imgui ALIAS imgui).
I would also recommend removing the variable IMGUI_DEMO_SRC
and instead modifying the add_library
call for the target imgui
to use a generator expression:
add_library (imgui STATIC imgui.cpp imgui_draw.cpp imgui_widgets.cpp $<$<BOOL:IMGUI_DEMO>:imgui_demo.cpp> )
@pumkinpal Agreed on all counts. The last one is a new trick - thanks for that :)