Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CMake build system #12

Closed
Youw opened this issue Jun 6, 2019 · 32 comments · Fixed by #288
Closed

CMake build system #12

Youw opened this issue Jun 6, 2019 · 32 comments · Fixed by #288
Labels
build system/CI Anything related to building the project or running on CI

Comments

@Youw
Copy link
Member

Youw commented Jun 6, 2019

As a common CMake user I'd suggest it is very convenient to have CMake supported by the project off-the-box.

A platform like MSVC would gain a great benefit - won't need to have MSVC-2010/2015/2017/2019/etc. separate projects.

I'm ready to prepare the whole infrastructure if the team/community don't have anything against it.

@Youw Youw added enhancement New feature or request build system/CI Anything related to building the project or running on CI labels Jun 6, 2019
@z3ntu
Copy link
Collaborator

z3ntu commented Jun 7, 2019

I'd rather use Meson as a build system than CMake

@todbot
Copy link
Contributor

todbot commented Jun 7, 2019

I would suggest that any new build system not prevent the use of simple Makefiles for the many small *nixes out there that don't have access to Python or Internet access.

@Youw
Copy link
Member Author

Youw commented Jun 10, 2019

I wouldn't suggest replacing build system. Not now.
NOTE1: Both Meson and CMake support generating Makefiles.
NOTE2: CMake doesn't require Python or Internet access.

I'd rather use Meson

Never used it. But quick reading over its readme/some docs, and it seems there is no much benefit in using Meson over CMake.
I'd also say, that CMake is way more widely used and known - it has proved itself, specially after version 3.x.

@z3ntu
Copy link
Collaborator

z3ntu commented Jun 10, 2019

NOTE1: Both Meson and CMake support generating Makefiles.

Meson actually generates files for the ninja build system 😉

In my opinion, Meson has a much better syntax than CMake and many useful features included (such as the pkg-config file generation, painless cross-compilation, etc)

There's also https://mesonbuild.com/Comparisons.html

I think it would be best to have manual Makefiles for those many small *nixes and a modern build system with all the fancy features you want for the rest (either cmake or meson)

@Youw
Copy link
Member Author

Youw commented Jun 10, 2019

ninja build system

I'd add it to cons for a project with a single .c file.

manual Makefiles

What would be a benefit of that effort? autotools already does it very well for all originally supported platforms.

Also, as I pointed since the beginning - on of the main benefit with CMake is to have a single build system, instead of MSVC-version specific copy-paste, XCode support appears automatically too, etc.

Mason with ninja only support - wouldn't make any difference here.

pkg-config file generation

Already done by current build system.
Trivially with CMake.

painless cross-compilation

Trivially with CMake.

@z3ntu
Copy link
Collaborator

z3ntu commented Jun 10, 2019

Sure, we can argue back and forth between Meson and CMake and nothing would change 😉 I'm for Meson, you're for CMake. Maybe others can chime in their thoughts :)

What would be a benefit of that effort? autotools already does it very well for all originally supported platforms.

From my point of view autotools is pretty complicated (and I have little experience with it) and manual Makefiles wouldn't be any longer than the autotools-equivalents probably. And as, per platform, it's mostly just a matter of compiling a single .c file into a .so file and installing the header file, manual Makefiles would work great for that - but, as said before, I'm pretty to open to any build system that works, I'll still continue to use my favorite in my own projects :)

@Qbicz
Copy link
Member

Qbicz commented Aug 30, 2019

I also prefer CMake to autotools, which I perceive as complicated. I have no experience with Meson.

One thing I can add to the discussion is that CMake can generate both ninja and Makefile buildsystem (just a matter of -GNinja flag).

@Youw
Copy link
Member Author

Youw commented Aug 30, 2019

CMake can generate both ninja and Makefile

and many others

I'll work on CMakeLists for hidapi

@Qix-
Copy link
Contributor

Qix- commented Sep 1, 2019

👎 on meson. The maintainer is not very collaborative and has very strange dogmatic ideas about build systems that just do not work in the real world. For example, if hidapi was used by a dependency-of-a-dependency, meson would prevent you from building due to how it structures subprojects. Cmake doesn't care much about how you structure your files, in contrast.

Also, if hidapi is used as a library for a build-time executable that is also built at build time (e.g. build EXE with hidapi as dep, then use the generated EXE as a tool to build another target), and the other target also uses hidapi, Meson will prevent the build because it thinks there will be a symbol collision - it tries to be smarter than you.

There have been very exhaustive discussions over at the Meson repository and none of them have resulted in any meaningful thought coming from the maintainer. I highly caution anyone against using Meson.

CMake is currently the industry standard, and while it isn't perfect it's definitely the most cooperative tool at the moment.

@Youw
Copy link
Member Author

Youw commented Jun 30, 2020

Making some progress: https://github.com/libusb/hidapi/tree/cmake-support

Before making a PR to master want to finish first:

  1. Autotools export files on install target (so CMake build system can be used instead of auto-tools for the same scenarios);
  2. CMake export files (a new feature - CMake users will benefit of it);

@bevanweiss
Copy link

Any chance of getting a rebase of cmake_support branch to include the latest commit on main?
Those Windows warnings would be nice to have tidied up in the cmake branch :)

@Youw
Copy link
Member Author

Youw commented Sep 8, 2020

Done.

But would be better if I put my mind and my hands into finishing the change and making a proper PR...

@bevanweiss
Copy link

Done.

But would be better if I put my mind and my hands into finishing the change and making a proper PR...

Thank you very much, greatly appreciated.

@bevanweiss
Copy link

I've just given the cmake-support branch a go. There is one issue encountered so far.
The application also uses libusb functionality directly, and so we already build libusb in as a static library.

Currently when trying to use HIDAPI_WITH_LIBUSB, there doesn't appear to be any way to pass in the libusb header location explicitly (and defer the static / shared library linkage), hence it throws up the CMake error about not having the required libusb dependency (from pkg_check_modules).

I'm quite a CMake noob... so perhaps there's an easy way around this, I just don't know it.

@Youw
Copy link
Member Author

Youw commented Oct 16, 2020

Well, it is not only a CMake configuration alone...

Since libusb officially provides only one method of delivery - build/install with autotools -> use pkg-config to find the installation - that is what being used by my implementation of CMake build system for hidapi. It uses pkg-config to find libusb and link against it.

One not very obvious, but method that should work in your case:
Generate a libusb-1.0.pc file somewhere in your build tree, that would contain paths to your own build of libusb (check official pattern for it in libusb repo).

Before including hidapi as your CMake subdirectory, set PKG_CONFIG_PATH (or ENV{PKG_CONFIG_PATH}) variable to path, where your generated libusb-1.0.pc is located.
It will allow hidapi to find your specific version of libusb and use it for build.

This looks like a workaround (and it kind of is), but it should work for you.

Meanwhile, I'll try to find a better solution.

@Youw
Copy link
Member Author

Youw commented Dec 3, 2020

Hi @bevanweiss,
check out cmake-libusb-improvement branch.
There you can define a CMake target usb-1.0 (e.g. an alias or interface library), befor including hidapi subdirectory in your CMake, and that target will be used instead of searching for for libusb with pkg-config.

@jm4R
Copy link
Contributor

jm4R commented Dec 11, 2020

@Youw thanks for your work already done to support cmake. It's a milestone! Could you please explain, how much ready is this branch today?

On my linux environment, I receive:

-- Checking for module 'libudev'
--   No package 'libudev' found

EDIT:
sory, I missed the package was searching by pkg-config so the libudev had to be installed by system package manager (apt).

Thanks again.

@Youw
Copy link
Member Author

Youw commented Dec 11, 2020

I think is is absolutely ready for Windows, macOS, Linux and Android.
I still have to make sure it works properly on BSD-like systems (e.g. FreeBSD), it may affect libusb backend a bit.
And document the usage properly.

Other then that, I believe it is ready. In fact, I'm personally using this branch in my own (private) project, and keeping it in sync with master.

so the libudev had to be installed by system package manager

yeap

@Qix-
Copy link
Contributor

Qix- commented Dec 11, 2020

@Youw could you open a PR with it (and preferably ping me? 🙂)

I have some suggestions about the current configuration.

@Youw
Copy link
Member Author

Youw commented Dec 11, 2020

@Qix- done: #220

@jm4R
Copy link
Contributor

jm4R commented Dec 21, 2020

@Youw did you try cross-compilation for arm64? It doesn't work for me:

-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE) 
CMake Error at /usr/local/share/cmake-3.18/Modules/FindPkgConfig.cmake:601 (message):
  pkg-config tool not found
Call Stack (most recent call first):
  /usr/local/share/cmake-3.18/Modules/FindPkgConfig.cmake:733 (_pkg_check_modules_internal)
  build/_deps/hidapi-src/linux/CMakeLists.txt:12 (pkg_check_modules)

-- Found PkgConfig: aarch64-linux-gnu-pkg-config (found version "0.29.1") 
-- Checking for module 'libusb-1.0>=1.0.9'
--   Found libusb-1.0, version 1.0.21
(...)
-- Configuring incomplete, errors occurred!
See also "/home/jenkins/workspace/ion_mpgg-1570/build/CMakeFiles/CMakeOutput.log".
See also "/home/jenkins/workspace/ion_mpgg-1570/build/CMakeFiles/CMakeError.log".
script returned exit code 1

I have both pkg-config as well as aarch64-linux-gnu-pkg-config installed.

@Youw
Copy link
Member Author

Youw commented Dec 21, 2020

I don't suppose you cross-compiled libusb first?

@jm4R
Copy link
Contributor

jm4R commented Dec 21, 2020

I don't suppose you cross-compiled libusb first?

I have pre-compiled version installed via apt (architecture arm64)

@Youw
Copy link
Member Author

Youw commented Dec 21, 2020

What is the package name you installed?
And please share the entire CMake command you're using.

@jm4R
Copy link
Contributor

jm4R commented Dec 21, 2020

For full cross-compilation:

apt-get install -y --no-install-recommends build-essential gcc-aarch64-linux-gnu g++-aarch64-linux-gnu ninja-build qemu-user-static pkg-config pkg-config-aarch64-linux-gnu
dpkg --add-architecture arm64
  1. Enable ubuntu bionic amd64 repositories

apt-get update
apt-get install -y --no-install-recommends libssl-dev:arm64 libudev-dev:arm64 libusb-1.0-0-dev:arm64
  1. hidapi is imported to my project via Cmake's FetchContent feature:
FetchContent_Declare(hidapi
    URL      https://github.com/libusb/hidapi/archive/7b5333301d4eb2d88f1f3be631cc49c2070eb50d.zip
    URL_HASH SHA256=8875a6c98aa0a81c3bb567d05ac5e18347bde539e164532d91265699aff24ece
)

...
FetchContent_GetProperties(hidapi)
if(NOT hidapi_POPULATED)
    FetchContent_Populate(hidapi)
    add_subdirectory(${hidapi_SOURCE_DIR} ${hidapi_BINARY_DIR})
endif()
  1. cmake toolchain file contains following modifications:
set(deb_gnu_type aarch64-linux-gnu)
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR aarch64)

set(CMAKE_C_COMPILER ${deb_gnu_type}-gcc)
set(CMAKE_CXX_COMPILER ${deb_gnu_type}-g++)
set(PKG_CONFIG_EXECUTABLE ${deb_gnu_type}-pkg-config)  # !!!!
set(CMAKE_CROSSCOMPILING_EMULATOR "qemu-aarch64-static;-L;/usr/aarch64-linux-gnu/")

The same configuration works good when using native amd64 architecture.

@jm4R
Copy link
Contributor

jm4R commented Dec 21, 2020

@Youw
I found a workaround. It seems that the following line from my CMAKE_TOOLCHAIN_FILE does not take any effect:

set(deb_gnu_type aarch64-linux-gnu)
set(PKG_CONFIG_EXECUTABLE ${deb_gnu_type}-pkg-config) # doesn't work?

When I set this from cmake's command line argument (-DPKG_CONFIG_EXECUTABLE=aarch64-linux-gnu-pkg-config), it works. I am not sure what is the reason of this behavior, maybe the variable is overriden to empty somewhere in between toolchain file execution and your CMakeLists.txt.

@jm4R
Copy link
Contributor

jm4R commented Dec 21, 2020

@Youw one more issue:

CMake Error at _deps/hidapi-build/src/linux/cmake_install.cmake:46 (file):
  file INSTALL cannot find
  "/path/to/proj/build/bin/libhidapi-hidraw.a": No
  such file or directory.

Call Stack (most recent call first):
  _deps/hidapi-build/src/cmake_install.cmake:73 (include)
  _deps/hidapi-build/cmake_install.cmake:47 (include)
  external/cmake_install.cmake:82 (include)
  cmake_install.cmake:47 (include)

This shows when using libusb backend - set(HIDAPI_WITH_LIBUSB ON). Instead of libhidapi-hidraw.a there is libhidapi-libusb.a in the specified directory.

@Youw
Copy link
Member Author

Youw commented Dec 21, 2020

Its been a while since I tried to cross-compile relatively large CMake project with a hand-made toolchain file. I usually get one from YOCTO or use the one provided by Android NDK - those work for my just fine.

I'll be able to try to repeat your steps later this week, maybe over the weekend.

Some thoughts from top of my mind:

PKG_CONFIG_EXECUTABLE

This is weird, I'd expect a variable set in toolchain file to be available everywhere. Maybe you need to make a full clean rebuild? This needs to be investigated more properly, but your workaround looks good to me.

set(CMAKE_CROSSCOMPILING_EMULATOR "qemu-aarch64-static;-L;/usr/aarch64-linux-gnu/")

Again, need to refresh my knowledge here, but it doesn't look obvious why do you need to set the last two parameters here.

file INSTALL cannot find...

This is a surprise. As I mentioned, I'll be able to check a bit later.


One more thing you could try:

add_subdirectory(${hidapi_SOURCE_DIR} ${hidapi_BINARY_DIR})

Add an src subdirectory of HIDAPI, instead of the root directory:
add_subdirectory(${hidapi_SOURCE_DIR}/src ${hidapi_BINARY_DIR})

This will give you the abitility to control build configuration in more details (check hidapi CMakeLists.txt in and /src directories, as I didn't document those yet). This will also allow you to disable standard install targets from hidapi CMake scripts, and make your own, if you need to.


Can you share your toolchain file too (as an attachment)? If I'd try what you do, best if I use exactly same configuration.

@jm4R
Copy link
Contributor

jm4R commented Dec 22, 2020

The pkg-config issue was on my side. The PKG_CONFIG_EXECUTABLE variable has to contain full, non-relative path so I've changed it to:

set(PKG_CONFIG_EXECUTABLE_NAME aarch64-linux-gnu-pkg-config)
find_program(PKG_CONFIG_EXECUTABLE ${PKG_CONFIG_EXECUTABLE_NAME})

and it works OK


hidapi_arm64_test.zip

For the last problem, please check out the attached minimal reproducible example. Just run:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=install
cmake --build build --target install

The example also contains toolchain file for arm64, but the last issue is reproducible on any architecture on Linux, so don't bother with cross-compiling.

@Youw
Copy link
Member Author

Youw commented Dec 27, 2020

Ok, I see the problem you have, @jm4R.

In your example, you add_subdirectory hidapi with EXCLUDE_FROM_ALL property.
Hidapi adds build/install targets for both linux backends: hidraw and libusb. But because of EXCLUDE_FROM_ALL - only one gets buit (the one you link against, which is libusb), and the other (hidraw) - doesn't. But since the install target is present for it (and it is not optional) - cmake tries to install target that wasn't built.
The error you get - is expected CMake behavior.

One of the simple options for you:

set(HIDAPI_WITH_HIDRAW OFF)

before

add_subdirectory(${hidapi_SOURCE_DIR}/src ${hidapi_BINARY_DIR})

NOTE1: I suggest you add_subdirectory an src subdirectory of hidapi, instead of the root folder, so you don't get HIDAPI-specific options as global options to your project.

NOTE2: if you do as NOTE1 suggests, you can also control whether to install hidapi or not by HIDAPI_INSTALL_TARGETS cmake varible.


I'll see if I can come up with more user-friendly solution of-the-box.

@jm4R
Copy link
Contributor

jm4R commented Dec 27, 2020

@Youw it's ok, but the variables you mentioned should be well documented. Or maybe the defaults could be different when build as non-root project (I think this is a common practice, yet I am not a cmake expert)

@Youw
Copy link
Member Author

Youw commented Dec 27, 2020

You're right about the documentation. That's why these changes are not in master. It is yet to be finished.

@Youw Youw closed this as completed in #288 Jul 3, 2021
@mcuee mcuee removed the enhancement New feature or request label Jul 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
build system/CI Anything related to building the project or running on CI
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants