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

macOS dylib minor version numbers differ between cmake and autotools builds #622

Open
ryandesign opened this issue Sep 3, 2023 · 5 comments
Labels
build system/CI Anything related to building the project or running on CI macOS Related to macOS backend

Comments

@ryandesign
Copy link
Contributor

When building hidapi 0.14.0 on macOS, the dynamic library's minor version information is different depending on whether cmake or autotools was used for the build.

With autotools:

% otool -L /opt/local/lib/libhidapi.dylib | head -n2
/opt/local/lib/libhidapi.dylib:
	/opt/local/lib/libhidapi.0.dylib (compatibility version 1.0.0, current version 1.0.0)

With cmake:

% otool -L /opt/local/lib/libhidapi.dylib | head -n2
/opt/local/lib/libhidapi.dylib:
	/opt/local/lib/libhidapi.0.dylib (compatibility version 0.0.0, current version 0.14.0)

With autotools the library's major version is 0 and its minor version is 1.0.0 (compatible back to minor version 1.0.0) whereas with cmake the library's major version is still 0 but its minor version has regressed to 0.14.0 (compatible back to minor version 0.0.0).

This is bad because the major and minor library version that was available at compile time is baked into each binary that uses the library. For example, here's a program that was built with hidapi-compiled-with-autotools:

% otool -L /opt/local/bin/mspdebug | head -n2
/opt/local/bin/mspdebug:
	/opt/local/lib/libhidapi.0.dylib (compatibility version 1.0.0, current version 1.0.0)

If I then replace libhidapi with one compiled with cmake, the program will not run*:

% mspdebug
dyld: Library not loaded: /opt/local/lib/libhidapi.0.dylib
  Referenced from: /opt/local/bin/mspdebug
  Reason: Incompatible library version: mspdebug requires version 1.0.0 or later, but libhidapi.0.dylib provides version 0.0.0
zsh: abort      mspdebug

This means that if a user wants to switch from hidapi compiled with autotools to hidapi compiled with cmake, they have to recompile all their software that links with libhidapi. This is a barrier to getting people to switch from autotools to cmake, as I believe you want us to do.

You have to be very careful to match your previous library version numbering scheme when switching to a different build system. libtool has a very special way of defining library versions that you have to follow. What's not explained there, because I guess they considered it an implementation detail that you didn't need to know about if you never stopped using libtool, is that library minor versions on macOS are 1.0.0 higher than on other operating systems because when Mac OS X was first introduced it could not handle library minor versions less than 1.0.0 but there was existing Unix software using libtool that specified library versions less than 1.0.0. macOS has been able to handle library minor versions less than 1.0.0 for a long time now but of course libtool can never remove that workaround or else projects' library minor versions would decrease when they updated libtool.

*What I did not realize until I researched it for this bug report is that Apple removed these library version checks completely in macOS 12, and in macOS 10.14(?) through macOS 11, it only runs the checks if the library was built for a macOS version earlier than 10.14. But since I'm sure you want your software to work on the widest range of systems possible, you should continue to follow the original spirit of the library minor version numbers by never letting them decrease (for any given major library version number; when the major library version number increases, of course the library minor version number can reset).

@mcuee mcuee added build system/CI Anything related to building the project or running on CI macOS Related to macOS backend labels Sep 4, 2023
@Youw
Copy link
Member

Youw commented Sep 4, 2023

This means that if a user wants to switch from hidapi compiled with autotools to hidapi compiled with cmake, they have to recompile all their software that links with libhidapi.

Can you elaborate what kind of software are you talking about?
I can't come up with a scenario where such happens and that is a blocker.
Based on #620 I only assume that "the software" is being developed/evolved (as it needs hidapi_darwin.h) so it will be re-compiled anyway.

@ryandesign
Copy link
Contributor Author

Can you elaborate what kind of software are you talking about?

I gave the example of mspdebug because it was one of the software programs in MacPorts that depends on hidapi and that has few other dependencies, but any software linking with the library would be affected.

Based on #620

That's a different matter. I'm a developer with MacPorts. The inciting incident that caused me to look into hidapi was the report to us five months ago that hidapi_darwin.h was not installed and my reencountering that issue yesterday. My investigation led me to discover that the cause was the difference in build system, so I filed #620. I discovered the recommendation to switch to cmake, which prompted me to investigate the viability of doing so, which led me to discover the dylib versioning difference and the inability (without workarounds, which we can use, with a little difficulty) to build both shared and static libraries at the same time.

@ryandesign
Copy link
Contributor Author

One difficulty in fixing the library versioning problem is that in the cmake build system you are using your project's version number as the library version number:

set_target_properties(hidapi_darwin
PROPERTIES
EXPORT_NAME "darwin"
OUTPUT_NAME "hidapi"
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
MACHO_COMPATIBILITY_VERSION ${PROJECT_VERSION_MAJOR}
FRAMEWORK_VERSION ${PROJECT_VERSION_MAJOR}
PUBLIC_HEADER "${HIDAPI_PUBLIC_HEADERS}"
)

These should not be coupled. There should be separate variables for the components of your library version number in the cmake build system as there already are in the autotools build system:

hidapi/configure.ac

Lines 8 to 15 in c19ae12

# Library soname version
# Follow the following rules (particularly the ones in the second link):
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
# http://sourceware.org/autobook/autobook/autobook_91.html
lt_current="0"
lt_revision="0"
lt_age="0"
LTLDFLAGS="-version-info ${lt_current}:${lt_revision}:${lt_age}"

@Youw
Copy link
Member

Youw commented Sep 4, 2023

TL;DR; version of the library built with CMake will remain unchanged by default.


These should not be coupled.

That is true if the project contains multiple components possibly of different versions or if the library has its own (different) versioning stategy.
As for HIDAPI - the library is the project. Everything else is just the helper infrastructure around it. At least this is the way I see it.

There should be separate variables

Most probably not a variable. The version of the library is not something that user should deside at build time.

as there already are in the autotools build system

As you may see from the blame - no one ever bothered to manage the library version with Autotools. The version always was 0.0.0 (or 1.0.0 because of the libtool behavior on macOS) and it makes no sense at all. I don't believe it was that way because someone designed it or that it has a special meaning - it is likely that way because no one really took care if it.
When I look at the library (e.g. with otool) I want to be able to know it version w/o checking with the package manager (in case of macOS - it could be a MacPorts, homebrew or no package manager at all, in which case - how do I check the version?).

In other words - I find current behavior of the Autotools to be a bug (e.g. #392) which is "fixed" in CMake.


But I totally understand the pain this may cause in scenarios like MacPorts when you upgrade only a single library w/o recompilation of all others.
I haven't consideret it earlier mostly because MacPorts is not the first package manager that has switched from Autotools to CMake and no one else had any problems with it. And if it wheren't for legacy behavior of libtool on macOS - MacPorts probably wouldn't hit this as an issue as well.

Specifically for cases like this one, I think it should suffise adding a macOS-specific CMake option HIDAPI_USE_LEGACY_LIBRARY_VERSION which when set to true would use version 1.0.0 for target/library version.

@ryandesign is there anything else stopping MacPorts from switching to CMake build system for HIDAPI?

@Youw
Copy link
Member

Youw commented Oct 23, 2023

@ryandesign please let me know what you think.

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 macOS Related to macOS backend
Projects
None yet
Development

No branches or pull requests

3 participants