pitchfork icon indicating copy to clipboard operation
pitchfork copied to clipboard

Question about playing nice with IDEs

Open nolange opened this issue 6 years ago • 4 comments

After some escapades with getting eclipse to behave nice, while not complicating a simple use-as-subdirectory I ended up with

src
    include
    CMakelist.txt (1)
test
    CMakelist.txt (2)
CMakelist.txt (3)

This would allow depended projects just pointing to (1) as subdirectory, or users just using this subdirectory to get to the lib/public includes quickly. Tests (2) could be similarly standalone, using the installed system libraries instead of the sources.

While (3) is primarily for aiding development and easy integration into IDEs (fitting defaults, incl unit tests).

I started with a similar layout like pitchfork, placing include at the root, but I got somewhat biased against that, as in practice header + sources are tied closer to each other than the remaining categories. for ex:

  • common git subtree for history
  • generating a public config.h fits more into the src directory (needs information from the build), but is semantically a installable include
  • they are typically installed together, so that should be done in one buildscriptfile (that I dont want in the root directory)

nolange avatar Apr 16 '19 11:04 nolange

What is your question? I don't understand what you're asking. Are you asking if this layout works?

Note the merged header placement. This would look like:

src
    my_library (0)
        // include files here
        // source files here as well
    CMakeLists.txt (1)
tests
    CMakeLists.txt (2)
CMakeLists.txt (3)

(0) contains all headers and source files. When you install the library, you install all *.hpp files and the build artifacts. Note that CMake can handle installs; you don't need a separate install script, but you can use one.

(3) is the main CMakeLists.txt, which should be viewed as the way to interact with the build system. (1) contains just the commands to set up my_library, (2) contains just the commands to test my_library.

Looking at your descriptions of combining headers and sources, I believe the merged header placement handles that.

Quincunx271 avatar Apr 16 '19 15:04 Quincunx271

My question would be if this layout did consider both use during development and build as dependency.

hierarchical (3) is on top, so you either have to verbosely configure everything (what to build and install) for development, release and use as library/submodule.

Another option would be to break it up and making all sub-directories usable standalone (without the top makefile, and going further without anything not below the directory). If you just want to use the library (headers being part of it), you could directly use the src directory, not the top directory. The top directory would deal with various compiler flags, and use conan for dependencies, while all this is strictly omitted below the src directory (so you could literally copy it over into another project without a mess of compiler settings). Smaller reusable parts, and cleaner structure IMHO, but that would require the include directory below the src directory.

And I would not use "merged headers", public headers would still be in a separate include directory, would be a mess to install otherwise.

nolange avatar Apr 16 '19 19:04 nolange

This layout does consider both use during development and use as a dependency.

I don't think there's a reasonable benefit to directly using the src/ directory when using a library as a dependency. The top (3) CMakeLists.txt can use conan for dependencies, it can set up compiler flags via add_compile_options and add_link_options, it can have project specific options, etc. Compile flags are part of the interface of a library; users cannot expect the library to work without it being able to set up flags. The user can use the root directory with add_subdirectory as one method of using this library as a dependency, and everything would work out fine.

The top (3) CMakeLists.txt should be the entry point for both development and use as a dependency.

If your concern is setting things in top (3) CMakeLists.txt which would affect the user, this can be avoided with the "Modern CMake" style of usage dependencies. No need to modify CMAKE_CXX_FLAGS, etc. You can hide conan or other project-specific settings if the root CMakeLists.txt was included as a subdirectory.


However, I think it would technically follow the pitchfork layout if you kept include/ under the root directory, and in the src/CMakeLists.txt (1), you pointed the include directory up to it:

target_include_directories(my_library
  PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}/../include"
)

The user could then depend on your library with add_subdirectory(my_library/src). This would mean that the user couldn't copy just the src/ folder into their project, but I don't think the user should expect to be able to do that.

I would not recommend doing this, though.

Quincunx271 avatar Apr 16 '19 19:04 Quincunx271

This layout does consider both use during development and use as a dependency.

I don't think there's a reasonable benefit to directly using the src/ directory when using a library as a dependency. The top (3) CMakeLists.txt can use conan for dependencies, it can set up compiler flags via add_compile_options and add_link_options, it can have project specific options, etc. Compile flags are part of the interface of a library; users cannot expect the library to work without it being able to set up flags.

Yes and no. there might be flags that are necessary (C/C++ standard, version + feature macros), but if you think of a library as sourcecode then more than that hurts. As concrete example, take some microprocessors like STM32 (Arm-based microcontrollers), if you want to use a library you would prefer to copy it over or use CMakes "add_subdirectory" to the src directory in the layout I outlined. Reason for that being is that the STM32 family has 100s of variants which differ in compiler parameters (ARM core, FPU, extensions). compiling everything with identical parameters is the only sane way here. I have also project just for some lowlevel startupcode and libraries which further depend on some macros, you cant build this standalone at all so the toplevel CMakeLists.txt is just for the IDE to grab include paths.

This doesnt go against what you say with conan and further configurations, toplevel should be the place to develop and build standalone packages. It should contain everything that's not absolutely crucial to compile the components of the project. Being able to use src standalone would be a testcase for this sort of modularity.

The user can use the root directory with add_subdirectory as one method of using this library as a dependency, and everything would work out fine.

not if it contains compiler parameters affecting the ABI, worst of all if you do it on a global level as you state as example. Even with "modern CMake" it might clash (particularly if those are usage requirements for headers), there should be only one toplevel CMakeLists.txt that defines such settings (or a toolchain file, or other "external sources").

Maybe some better example, if you want to convert a multiple of single-library-projects into one with submodules, then you will do exacly that: take out everything not specific to the library and concentrate the rest in the toplevel CMakeLists.txt.

The top (3) CMakeLists.txt should be the entry point for both development and use as a dependency.

If your concern is setting things in top (3) CMakeLists.txt which would affect the user, this can be avoided with the "Modern CMake" style of usage dependencies. No need to modify CMAKE_CXX_FLAGS, etc. You can hide conan or other project-specific settings if the root CMakeLists.txt was included as a subdirectory.

Still wont help if a subdirectory decides to compile as no-pic and you want to use it in a shared library, or if 2 subdirectories have conflicting usage requirements for their respective headers (which you use both - at the same time). Sure you can build projects where this wont happen, but how would you specify rules that wont happen? If such options aren't allowed at all, then thats a rather simple rule =)

However, I think it would technically follow the pitchfork layout if you kept include/ under the root directory, and in the src/CMakeLists.txt (1), you pointed the include directory up to it:

target_include_directories(my_library
  PUBLIC
    "${CMAKE_CURRENT_SOURCE_DIR}/../include"
)

The user could then depend on your library with add_subdirectory(my_library/src). This would mean that the user couldn't copy just the src/ folder into their project, but I don't think the user should expect to be able to do that.

I would not recommend doing this, though.

Its a pedantic approach of never going up or sideways, it helps keeping a hierarchy.

Sorry, if you think that's going nowhere, I am rather keen of solving these issues (project layout) for myself and am looking at approaches and particularly their differences closely. Independent (as much as possible) subprojects in src/libs and tests seem to make alot sense to me, you need a toplevel CMakefile.txt for a distributable/packageable binary (defining consistent compiler options for all sub-folders/projects).

nolange avatar Apr 16 '19 20:04 nolange