Re: [xz-devel] Compatibility between CMake config file and FindLibLZMA.cmake

2021-02-14 Thread Markus Rickert

I'm afraid I didn't I fully understand the exact situation when this
problem occurs. I trust that it's real and that you tested it, thus
I committed this change. Thanks! I assume it has no significant
downsides compared to the ALIAS method.


Thanks, I just tested this and it also works for this use case now. 
There is no downside compared to the ALIAS method.



Can something go wrong in the opposite direction: CMakeLists.txt
recommends that one uses "find_package(liblzma 5.2.5 REQUIRED CONFIG)"
to ensure that FindLibLZMA isn't used. If one does so and then
something else in the project uses FindLibLZMA anyway, does the
interface library (or previously the alias) cause a problem? Or is this
situation unlikely to happen?


When you specify "CONFIG" in find_package(), CMake always looks for the 
config file and does not look for a module. The only available target 
definitions are therefore the ones in the config file, with the 
interface library providing backward compatibility with the CMake module 
and its LibLZMA::LibLZMA target.



In the CMake world, perhaps it could matter when two things are able to
use liblzma but only one of them needs encoding support. Then those
variables could help to keep the build working. However, it wouldn't
suprise me if most packages don't check those variables and simply
assume that all features are available if liblzma is found (which I
think is reasonable behavior). I didn't try to verify this though so I
may be wrong.


So far I haven't checked these variables when adding liblzma as a 
dependency. Having a matching variable in the config file if the library 
can be configured with certain options enabled or disabled can however 
be quite helpful depending on the use case. For this, CMake provides an 
option() command and the respective variable can be added to the config 
file.



This can be done too, although first it should be decided if full
compatibility with FindLibLZMA is desirable. I guess FindLibLZMA won't
see major changes so maintaining compatibility wouldn't need frequent
changes in the liblzma config file.


Having access to the version information in CMake variables is also 
quite useful, e.g., if features change. Otherwise these have to be 
extracted from header files or via library functions.



FindLibLZMA also sets LIBLZMA_LIBRARIES and LIBLZMA_INCLUDE_DIRS. Is it > OK to 
not care about these in context of FindLibLZMA compatibility?


The LIBLZMA_LIBRARIES and LIBLZMA_INCLUDE_DIRS are mostly for backward 
compatibility if targets are not used and contain absolute paths to the 
libraries and headers, including dependencies. The LibLZMA::LibLZMA 
target is included in FindLibLZMA.cmake starting with CMake 3.14.


This information can be extracted from the target via 
get_target_property(), but the property names depend on the platform and 
build types, e.g.:

https://gitlab.gnome.org/GNOME/libxml2/-/blob/cbe1212db6e22fa92c33242c3ce089476585f872/libxml2-config.cmake.cmake.in#L33-58
https://gitlab.gnome.org/GNOME/libxml2/-/blob/cbe1212db6e22fa92c33242c3ce089476585f872/libxml2-config.cmake.cmake.in#L79


I was thinking if the naming should have been such that it doesn't
overlap or conflict with FindLibLZMA module at all. However, that would
mean that if one thing depends on, for example, xz_liblzma::xz_liblzma
and another thing on LibLZMA::LibLZMA, then two different targets would
refer to the same library and so the compiler and linker flags would be
duplicated. I'm not sure if that could become a problem.


As a user I think it would be nice to be able to use the config file 
instead of the module without major changes, otherwise this always has 
to be considered when trying to support multiple platforms and versions. 
Keeping LibLZMA::LibLZMA would therefore be the easiest option, but I 
can also understand if you prefer to correct the name. The new interface 
library definition (LibLZMA::LibLZMA -> liblzma::liblzma) already helps 
a lot in supporting both.


It will take some time for all platforms and package managers to include 
the config file. For this, it would probably also have to be generated 
when building via autotools.



I have always written liblzma in lower case so changing the primary
target name to LibLZMA::LibLZMA would look a bit funny to me. Of
course, I'm fine with it still if it means that things work better
overall.


LibXml2 and LibXslt have similar issues. In the end I kept the mixed 
case of the module names for compatibility reasons.


The FindLibLZMA.cmake module could probably also be updated to include 
the lowercase target name with a deprecation message.



If I change the main add_library(liblzma ) to add_library(LibLZMA
) then the filename will be LibLZMA.something too. That isn't
good because then one cannot replace a CMake-built shared liblzma with
an Autotools-built one on operating systems where file and library
names are case sensitive.



You can either change the target name directly and change the filename 

Re: [xz-devel] Compatibility between CMake config file and FindLibLZMA.cmake

2021-02-13 Thread Lasse Collin
On 2021-01-31 Markus Rickert wrote:
> I noticed however, that there is still an issue when building against
> a library that was built against liblzma due to using ALIAS (e.g., 
> testproject -> LibXml2 -> LibLZMA):
> CMake will resolve the alias to include "liblzma::liblzma" instead of 
> "LibLZMA::LibLZMA" in the LibXml2 link dependencies. When another 
> library does not set CMAKE_FIND_PACKAGE_PREFER_CONFIG, it will
> however still use FindLibLZMA and is then not able to resolve the 
> "liblzma::liblzma" dependency.
> 
> With the following alternative (that is also used in the CMake
> exported target files), LibXml2 will continue to use
> "LibLZMA::LibLZMA" in its dependencies when linking against this
> target:
> add_library(LibLZMA::LibLZMA INTERFACE IMPORTED)
> set_target_properties(LibLZMA::LibLZMA PROPERTIES 
>   INTERFACE_LINK_LIBRARIES liblzma::liblzma)

I'm afraid I didn't I fully understand the exact situation when this
problem occurs. I trust that it's real and that you tested it, thus
I committed this change. Thanks! I assume it has no significant
downsides compared to the ALIAS method.

Can something go wrong in the opposite direction: CMakeLists.txt
recommends that one uses "find_package(liblzma 5.2.5 REQUIRED CONFIG)"
to ensure that FindLibLZMA isn't used. If one does so and then
something else in the project uses FindLibLZMA anyway, does the
interface library (or previously the alias) cause a problem? Or is this
situation unlikely to happen?

> >- FindLibLZMA sets a few CMake cache variables that the config
> >  file doesn't, for example, LIBLZMA_HAS_EASY_ENCODER. I have no
> >  idea if there are packages that care about this.  
> 
> This seems to be due to the autotools options for enabling/disabling 
> certain encoders and decoders. If there is no equivalent CMake option 
> for modifying this you could add variables to the config files that
> are always set to ON:
> set(LIBLZMA_HAS_AUTO_DECODER ON)
> set(LIBLZMA_HAS_EASY_ENCODER ON)
> set(LIBLZMA_HAS_LZMA_PRESET ON)

Autotools options being the reason sounds reasonable, although all
normal builds of liblzma always have all features enabled. However, I
might add CMake options to disable encoder or decoder because there are
use cases where encoder support isn't needed. Then those compatibility
variables would need to be set conditionally too.

If liblzma is built with some features disabled and then something
breaks, I'm not sure if I should care. With Autotools-based builds
no help is provided: if one wants to disable features to reduce the
library size, one must be careful to do it without breaking anything.

In the CMake world, perhaps it could matter when two things are able to
use liblzma but only one of them needs encoding support. Then those
variables could help to keep the build working. However, it wouldn't
suprise me if most packages don't check those variables and simply
assume that all features are available if liblzma is found (which I
think is reasonable behavior). I didn't try to verify this though so I
may be wrong.

> The entries for LIBLZMA_VERSION_MAJOR etc. can also be easily added
> to the file:
> set(LIBLZMA_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
> set(LIBLZMA_VERSION_MINOR ${PROJECT_VERSION_MINOR})
> set(LIBLZMA_VERSION_PATCH ${PROJECT_VERSION_PATCH})
> set(LIBLZMA_VERSION_STRING \"${PROJECT_VERSION}\")

This can be done too, although first it should be decided if full
compatibility with FindLibLZMA is desirable. I guess FindLibLZMA won't
see major changes so maintaining compatibility wouldn't need frequent
changes in the liblzma config file.

FindLibLZMA also sets LIBLZMA_LIBRARIES and LIBLZMA_INCLUDE_DIRS. Is it
OK to not care about these in context of FindLibLZMA compatibility?

> > Perhaps there are other details affecting compatiblity. I just
> > wonder how big mistake it was to use liblzma::liblzma in the config
> > file. I guess it's too late to change it now.  
> 
> By using the same principle as above, you should still be able to
> change this if you prefer. In that case, liblzma::liblzma can be an
> alias for LibLZMA::LibLZMA in the config file.

I was thinking if the naming should have been such that it doesn't
overlap or conflict with FindLibLZMA module at all. However, that would
mean that if one thing depends on, for example, xz_liblzma::xz_liblzma
and another thing on LibLZMA::LibLZMA, then two different targets would
refer to the same library and so the compiler and linker flags would be
duplicated. I'm not sure if that could become a problem.

I have always written liblzma in lower case so changing the primary
target name to LibLZMA::LibLZMA would look a bit funny to me. Of
course, I'm fine with it still if it means that things work better
overall.

> I think the CMake build files also were not yet included in any
> official release.

CMakeLists.txt and friends were included in XZ Utils 5.2.5 (with the
bug that shared library doesn't build on Windows). It's 

Re: [xz-devel] Compatibility between CMake config file and FindLibLZMA.cmake

2021-01-31 Thread Markus Rickert

I have committed both of your suggestions (hopefully correctly). Thanks!


Thanks, I just tested this and it works correctly when building directly 
against liblzma via CMake, both with config and module mode.


I noticed however, that there is still an issue when building against a 
library that was built against liblzma due to using ALIAS (e.g., 
testproject -> LibXml2 -> LibLZMA):
CMake will resolve the alias to include "liblzma::liblzma" instead of 
"LibLZMA::LibLZMA" in the LibXml2 link dependencies. When another 
library does not set CMAKE_FIND_PACKAGE_PREFER_CONFIG, it will however 
still use FindLibLZMA and is then not able to resolve the 
"liblzma::liblzma" dependency.


With the following alternative (that is also used in the CMake exported 
target files), LibXml2 will continue to use "LibLZMA::LibLZMA" in its 
dependencies when linking against this target:

add_library(LibLZMA::LibLZMA INTERFACE IMPORTED)
set_target_properties(LibLZMA::LibLZMA PROPERTIES 
INTERFACE_LINK_LIBRARIES liblzma::liblzma)



   - FindLibLZMA doesn't #define LZMA_API_STATIC when building against
 static liblzma. LZMA_API_STATIC omits __declspec(dllimport) from
 liblzma function declarations on Windows.


The FindLibLZMA module cannot easily determine if a detected library was 
built as shared or static library (there is an open issue for this [1]) 
without looking at header or config files. autotools seems to build both 
at the same time and FindLibLZMA will link the shared version if it is 
available.


CMake builds either static or shared via BUILD_SHARED_LIBS, but includes 
the correct compiler definition in the exported target.



   - FindLibLZMA sets a few CMake cache variables that the config file
 doesn't, for example, LIBLZMA_HAS_EASY_ENCODER. I have no idea if
 there are packages that care about this.


This seems to be due to the autotools options for enabling/disabling 
certain encoders and decoders. If there is no equivalent CMake option 
for modifying this you could add variables to the config files that are 
always set to ON:

set(LIBLZMA_HAS_AUTO_DECODER ON)
set(LIBLZMA_HAS_EASY_ENCODER ON)
set(LIBLZMA_HAS_LZMA_PRESET ON)

The entries for LIBLZMA_VERSION_MAJOR etc. can also be easily added to 
the file:

set(LIBLZMA_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set(LIBLZMA_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set(LIBLZMA_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set(LIBLZMA_VERSION_STRING \"${PROJECT_VERSION}\")


   - The config file has find_dependency(Threads) while FindLibLZMA
 doesn't. This can affect the linker flags.


Other find modules have similar issues. FindLibXml2 for instance also 
does not link against dependencies such as Iconv or LibLZMA. For 
link-only dependencies this issue only shows up in static builds. The 
config file should still include the correct dependencies.



Perhaps there are other details affecting compatiblity. I just wonder
how big mistake it was to use liblzma::liblzma in the config file. I
guess it's too late to change it now.


By using the same principle as above, you should still be able to change 
this if you prefer. In that case, liblzma::liblzma can be an alias for 
LibLZMA::LibLZMA in the config file. I think the CMake build files also 
were not yet included in any official release.


You can add an alias for target "liblzma" to target "LibLZMA" in the 
CMakeLists.txt file (after the target definition in add_library, line 
193) for users that embed the xz project as a subdirectory:

add_library(LibLZMA::LibLZMA ALIAS LibLZMA)
add_library(liblzma ALIAS LibLZMA::LibLZMA)
add_library(liblzma::liblzma ALIAS LibLZMA::LibLZMA)

With CMake >3.17, you can further set a deprecation message for the old 
target name (works only on INTERFACE IMPORTED, not on ALIAS):

if(NOT CMAKE_VERSION VERSION_LESS 3.17)
  set_property(TARGET liblzma::liblzma PROPERTY DEPRECATION "Deprecated 
target. Please use LibLZMA::LibLZMA instead.")

endif()

Best regards,

Markus Rickert

[1] https://gitlab.kitware.com/cmake/cmake/-/issues/18564


smime.p7s
Description: S/MIME cryptographic signature


Re: [xz-devel] Compatibility between CMake config file and FindLibLZMA.cmake

2021-01-30 Thread Lasse Collin
On 2021-01-23 Markus Rickert wrote:
> This could be solved by adding an alias to the config file:
> add_library(LibLZMA::LibLZMA ALIAS liblzma::liblzma)
> 
> An additional improvement would be to enable this on case-sensitive
> file systems as well. For this, the config file would need to be
> renamed from liblzmaConfig.cmake to liblzma-config.cmake (and the
> version file to liblzma-config-version.cmake), see [2].

I have committed both of your suggestions (hopefully correctly). Thanks!

Some extra thoughts: There are some differences between FindLibLZMA and
the config file:

  - FindLibLZMA doesn't #define LZMA_API_STATIC when building against
static liblzma. LZMA_API_STATIC omits __declspec(dllimport) from
liblzma function declarations on Windows.

  - FindLibLZMA sets a few CMake cache variables that the config file
doesn't, for example, LIBLZMA_HAS_EASY_ENCODER. I have no idea if
there are packages that care about this.

  - The config file has find_dependency(Threads) while FindLibLZMA
doesn't. This can affect the linker flags.

Perhaps there are other details affecting compatiblity. I just wonder
how big mistake it was to use liblzma::liblzma in the config file. I
guess it's too late to change it now.

-- 
Lasse Collin  |  IRC: Larhzu @ IRCnet & Freenode