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

Library targets are a mess #3909

Open
ben-clayton opened this issue Oct 13, 2020 · 7 comments
Open

Library targets are a mess #3909

ben-clayton opened this issue Oct 13, 2020 · 7 comments

Comments

@ben-clayton
Copy link
Contributor

Pulling together the following issues:

To summarize the above:

BUILD_SHARED_LIBS is not properly respected, and distro packages are now broken

This is mostly my fault - #3490 fixed Windows builds that had issues building .dlls (#3482), but these changes have caused distro package problems (#3626). Some background:

Prior to #3490, we had "just" the SPIRV_TOOLS targets ${SPIRV_TOOLS} and ${SPIRV_TOOLS}-shared:

  • ${SPIRV_TOOLS} was either static or shared based on BUILD_SHARED_LIBS and had all symbols visible as default (symbols not annotated with SPIRV_TOOLS_EXPORT were also exposed)
  • ${SPIRV_TOOLS}-shared was (and still is) always shared and hides non-pubic-API symbols (only SPIRV_TOOLS_EXPORT symbols are visible).

Both libSPIRV-Tools.so and libSPIRV-Tools-shared.so appear to be included in distro packages.

With #3490:

  • ${SPIRV_TOOLS} was renamed to ${SPIRV_TOOLS}-static and was forced to always build as static.
  • ${SPIRV_TOOLS} is now an alias to ${SPIRV_TOOLS}-static or ${SPIRV_TOOLS}-shared based on BUILD_SHARED_LIBS.
  • Targets that previously depended on ${SPIRV_TOOLS} now depend on ${SPIRV_TOOLS}-static.
  • Other library targets always build as static.

While the changes work transparently when using SPIRV-Tools as a sub-project of another CMake project, it breaks the install package, as these were expecting all libraries to be generated as shared when BUILD_SHARED_LIBS=1.

I can only speculate that the reason we originally had the ${SPIRV_TOOLS} and ${SPIRV_TOOLS}-shared targets was due to symbol visibility - there are a number of targets in this project that depend on ${SPIRV_TOOLS} and use non-public APIs. This is discussed here.

Libraries are not versioned

None of the libraries are versioned, there's no use of versioned SONAMEs. Discussed in detail here.
Consequently, updating to a new version of SPIRV-Tools may break projects in a number of exciting ways.


I propose the following:

  1. We replace the ${SPIRV_TOOLS}, ${SPIRV_TOOLS}-shared and ${SPIRV_TOOLS}-static targets with a single ${SPIRV_TOOLS} target that respects BUILD_SHARED_LIBS

The ${SPIRV_TOOLS} target will hide non-public APIs by default (same for static as shared).

Non public symbols in use by other SPIRV-Tools targets will need to be moved out to other static utility libraries (which will not be included in the install output) that can be privately linked by both ${SPIRV_TOOLS} and other dependee targets.

As the ${SPIRV_TOOLS}-static target has not been hiding private symbols, there's a good chance that external projects are relying on these private APIs. These will have to be fixed, or we need to promote more of the library from private to public.

This will also require fixing up downstream projects that explicitly use ${SPIRV_TOOLS}-static (examples: clspv, dxc) and ${SPIRV_TOOLS}-shared.

Distros will likely have to remove the libSPIRV-Tools-shared.so library from their packages.

  1. We start versioning our shared libraries with VERSION and SOVERSION

The version numbers will be derived from the CHANGES file, and so will always be kept in sync with the source.

  1. We start enforcing semantic versioning rules

We enforce a major version bump whenever there's a breaking API / ABI change to the public API.
We enforce a minor version bump whenever there's backwards-compatible, but new public APIs added.

I have been working on tooling for detecting and enforcing this as part of presubmits.

  1. We classify the public API for SPIRV-Tools[-link,-opt,-reduce]

The ${SPIRV_TOOLS} target attempts to classify public from non-public API using the SPIRV_TOOLS_EXPORT macro.

In order to version the other libraries, we'll need to limit the symbol visibility to well defined public API, otherwise any change to these targets will technically break API / ABI compatibility.

If no public API can be found, we should question the inclusion of these libraries in package distributions.


I'm aware that these proposals will likely cause breakages for downstream projects, but I believe the long-term benefits outweigh the short term pain.

Thoughts and comments welcome.

ben-clayton added a commit to ben-clayton/SPIRV-Tools that referenced this issue Oct 13, 2020
If enabled the following targets will be created:

* `${SPIRV_TOOLS}-static` - `STATIC` library. Has full public symbol visibility.
* `${SPIRV_TOOLS}-shared` - `SHARED` library. Has default-hidden symbol visibility.
* `${SPIRV_TOOLS}`        - will alias to one of above, based on BUILD_SHARED_LIBS.

If disabled the following targets will be created:

* `${SPIRV_TOOLS}`        - either `STATIC` or `SHARED` based on the new `SPIRV_TOOLS_LIBRARY_TYPE` flag. Has full public symbol visibility.
* `${SPIRV_TOOLS}-shared` - `SHARED` library. Has default-hidden symbol visibility.

Defaults to `ON`, matching existing build behavior.

This flag can be used by package maintainers to ensure that all libraries are build as shared objects.

Issue: KhronosGroup#3626
See also: KhronosGroup#3909
@orbea
Copy link

orbea commented Nov 6, 2020

@ben-clayton I would suggest that both shared and static libs could be individually enabled or disabled so that packages could be created with only shared libs, only static libs or both.

@expipiplus1
Copy link
Contributor

This is important for build systems which aren't able to build the shared lib, for example nixpkgs's pkgsStatic: NixOS/nixpkgs#103197

@barcharcraz
Copy link

@ben-clayton I would suggest that both shared and static libs could be individually enabled or disabled so that packages could be created with only shared libs, only static libs or both.

This doesn't really work in cmake very well. I would suggest just looking at BUILD_SHARED_LIBS and building shared libraries if it's set and static otherwise (just call add_library without a library type and you get this behavior). For the symbol issue you should use "object" libraries, either directly or to build seperate internal static libraries that have the symbols you need. And these should NOT be installed.

Alternatively you should just export all the symbols you need to export and document which ones are "stable" and which ones aren't. You could also have seperate shared libs with the "internal" symbols that are linked to by the libs providing the "stable" symbols, but that's probably more complicated than necessary and it doesn't seem like your project really wants to commit to the stability requirements to make in place upgrades possible (it's a huge commitment).

I may prepare a patch to do this but it's likely to be somewhat disruptive to the whole vulkan-sdk cluster of dependencies.

@sl1pkn07
Copy link
Contributor

Thoughts and comments welcome.

sincerely as user, all you points is how should It have been things from the start. and a year has passed and none of the point is move.

this must do have done in the next day when the error opened. be cause affect a lot of projects and distributions

exist any ETA programed for fix this?

greetings

sl1pkn07 added a commit to sl1pkn07/SPIRV-Tools that referenced this issue Oct 12, 2021
- Try to fix the point (1).
  - Let's visible always. because hide make problems when link to sprv-foo/test programs in shared mode (can' find any symbols).
- Build external RE2 in static mode always

TODO:
  - Fix point (2) and point (3)

- Point (4) is out of my scope. i'm not coder
sl1pkn07 added a commit to sl1pkn07/SPIRV-Tools that referenced this issue Oct 12, 2021
- Try to fix the point (1).
  - Build static mode by default (like always). for enable shared mode set `-DBUILD_SHARED_LIBS=ON`
  - Remove reneration SPIRV-Tools-shared.pc.in. not need anymore. SPIRV-Tools.pc.in can handle both.
  - Let's visible always. because hide make problems when link to sprv-foo/test programs in shared mode (can' find any symbols).
- Build external RE2 in static mode always

TODO:
  - Fix point (2) and point (3)

- Point (4) is out of my scope. i'm not coder
@sl1pkn07
Copy link
Contributor

#4569

please test

i do it in local and do ctest in both mode. the test passed without problems

for run ctest in shared lib. is need ad the paths of the generated .so to LD_LIBRARY_PATH, like

  LD_LIBRARY_PATH="$(pwd)/source:$(pwd)/source/link:$(pwd)/source/lint:$(pwd)/source/opt:$(pwd)/source/reduce" \
  ctest --output-on-failure

greetings

@ben-clayton
Copy link
Contributor Author

Hi @sl1pkn07,

sincerely as user, all you points is how should It have been things from the start. and a year has passed and none of the point is move.
this must do have done in the next day when the error opened. be cause affect a lot of projects and distributions

I attempted to find a clean solution to these problems, but found that there are numerous downstream projects depending on the current build rules and behavior. The minor changes I attempted to improve the situation broke people's workflows, and people got grumpy (understandably).

I came to the conclusion that the only sensible approach to fixing this is to make a v2 branch, and make significant breaking changes there. Unfortunately my priorities have changed over the past year, so I'm unlikely to be able to drive this effort.

I'll review your PR, but I'd be extremely cautious of making significant build rule / linker changes to the main branch. There are a lot of projects that depend on SPIRV-Tools, and have (probably undesirably) come to depend on the broken behavior of this library.

I don't want to discourage any efforts to fix this, but I'd still strongly encourage large changes to be made in different branch.

@sl1pkn07
Copy link
Contributor

For that i put the PR as draft

About downstream projects, I'm completely sure rigth now have a workrounds for fixing the actual behaviour, and the devs want to remove it as soon as possible.

This is a chance to do that correctly.

Greetings

sl1pkn07 added a commit to sl1pkn07/SPIRV-Tools that referenced this issue Oct 16, 2021
- Try to fix the point (1).
  - Build static unconditionally. but is only used for link all `spirv-foo` programs. because all of them (or partial) need all symbols which is only provided by static libs. for install it. see below
    This can increase the size a bit.
  - Now exist two defines witch control what type of library is installed/builded*:
     - `SPIRV_TOOLS_BUILD_SHARED_LIBS`   -> this control if you want build shared libs. and if is builded, install it when invoke `make install`
     - `SPIRV_TOOLS_INSTALL_STATIC_LIBS` -> this not control the build static library (because is ON unconditionality), but can control the installation when invoke `make install`
     -- I do this because some distros needs only static libs, other only shared libs, other both, or other simply what install only the programs
     --- Table of individual use:

        `SPIRV_TOOLS_BUILD_SHARED_LIBS` not set   -> Disable build and installation of shared libraries
        `SPIRV_TOOLS_BUILD_SHARED_LIBS=ON'        -> Enable build and install shared libs
        `SPIRV_TOOLS_INSTALL_STATIC_LIBS` not set -> Enable by default. enable the installation the libraries when invoke `make install`
        `SPIRV_TOOLS_INSTALL_STATIC_LIBS=ON`      -> Same as not set

    --- Table of conjuntion use:

        `SPIRV_TOOLS_BUILD_SHARED_LIBS=ON'  and `SPIRV_TOOLS_INSTALL_STATIC_LIBS=ON`  -> Build and install the wrole project. include programs, static and shared libs
        `SPIRV_TOOLS_BUILD_SHARED_LIBS=OFF' and `SPIRV_TOOLS_INSTALL_STATIC_LIBS=ON`  -> Build the programs and static libs, and install the static libs and the programs when invoke `make install` (Default)
        `SPIRV_TOOLS_BUILD_SHARED_LIBS=ON'  and `SPIRV_TOOLS_INSTALL_STATIC_LIBS=OFF` -> build the programs, shared and static libs, and only install the programs and the shared libs when invoke `make install`
        `SPIRV_TOOLS_BUILD_SHARED_LIBS=OFF' and `SPIRV_TOOLS_INSTALL_STATIC_LIBS=OFF` -> build the programs and the static libs, but not install when invoke `make install`

       * In all cases, always install the headers

  - The generation of the `.cmake` files is changed. now generate two flavors: one for static (without any sufix), and other for shared (whit `shared` sufix). both can install with the two defines described above. (and not colided between both)
    -- This need HARD test. this need a CMakeLists.txt test case wich can get the info when use static libs or use shared libs. and test if can linked with other things.
       I have desing this for can coinstall shared and static in same time, an let the user what need in your project. cmake can search one or other with only need add `STATIC` or `SHARED` in the `findpackage(FOO >TYPE<)`.
  - The files `libSPIRV-Tools-shared.so` and `SPIRV-Tools-shared.pc` is completely gone. no need anymore. is a duplicate lib when build shared libs, and useless whe build static libs (who ise a shared lib when the dev use static libs?)
  - By design, the common `SPIRV-Tools.pc` can be used in both build modes. the `pkg-config` stack can handle the information of static libs with `--static` flag when exist static libs in the library path, and normal use when is used as shared lib.
    Maybe need ajust for include this information (if exist in the project) into `SPIRV-Tools.pc.in` and setup in the `CMakeFiles.txt`.
  - The visiblility of the shared/static libs is untouched: Hiden for `libSPIRV-Tools.so` and full visible for static.. the other libs originally have ones hiden and other full visible. i leave it untouch. but need test if is all ok.

TODO:
  - Fix point (2) and point (3)

- Point (4) is out of my scope. i'm not coder
sl1pkn07 added a commit to sl1pkn07/SPIRV-Tools that referenced this issue Oct 18, 2021
- Try to fix the point (1).
  - Build static unconditionally. but is only used for link all `spirv-foo` programs. because all of them (or partial) need all symbols which is only provided by static libs (until the point 4 get fixed)(*). for install it. see below
    This can increase the size a bit.
  - Now exist two defines witch control what type of library is installed/builded*:
     - `BUILD_SHARED_LIBS`         -> This control if you want build shared libs. and if is builded, install it when invoke `make install`
     - `SPIRV_INSTALL_STATIC_LIBS` -> This not control the build static library (because is ON unconditionality), but can control the installation when invoke `make install`
     -- I do this because some distros needs only static libs, other only shared libs, other both, or other simply what install only the programs
     --- Table of individual use:

        `BUILD_SHARED_LIBS=OFF` or not set          -> Disable build and installation of shared libraries
        `BUILD_SHARED_LIBS=ON'                      -> Enable build and install shared libs
        `SPIRV_INSTALL_STATIC_LIBS=OFF`             -> Disable the installation the libraries when invoke `make install`
        `SPIRV_INSTALL_STATIC_LIBS=ON` or not set   -> Option ON by default. Enable the installation when invoke `make install`

    --- Table of conjuntion use:

        `BUILD_SHARED_LIBS=ON'  and `SPIRV_INSTALL_STATIC_LIBS=ON`  -> Build and install the wrole project. include programs, static and shared libs
        `BUILD_SHARED_LIBS=OFF' and `SPIRV_INSTALL_STATIC_LIBS=ON`  -> Build the programs and static libs, and install the static libs and the programs when invoke `make install` (Default)
        `BUILD_SHARED_LIBS=ON'  and `SPIRV_INSTALL_STATIC_LIBS=OFF` -> build the programs, shared and static libs, and only install the programs and the shared libs when invoke `make install`
        `BUILD_SHARED_LIBS=OFF' and `SPIRV_INSTALL_STATIC_LIBS=OFF` -> build the programs and the static libs, but not install when invoke `make install`

       * In all cases, always install the headers

  - The generation of the `.cmake` only make one flavor, but depend of the options is used, include shared, static, or both. when enable only static lib, the `.cmake` files point to `static` libs, when build only shared libs, points to `shared' libs,
    in this case, static and shared uses the both cases, uses the same TARGET (`libSPIRV-Tools>foo<`)
    If enabled both, the TARGET of the static libs is untouched (`libSPIRV-Tools>foo<`), but the shared libs add the surfix `-shared` (`libSPIRV-Tools>foo<-shared`)
    -- This need HARD test. this need a CMakeLists.txt test case wich can get the info when use static libs or use shared libs. and test if can linked with other things.
       I have tested with GLSLANG, and seems work as expected. in a VKD3D project (uses pkg-config), i need remove the `-shared` in the configure.am file for found the correct library.. build ok and linked the libraries as expected (*)
  - The files `libSPIRV-Tools-shared.so` and `SPIRV-Tools-shared.pc` is completely gone. no need anymore.
  - By design, the common `SPIRV-Tools.pc` can be used in both build modes. the `pkg-config` stack can handle the information of static libs with `--static` flag when exist static libs in the library path, and normal use when is used as shared lib.
    Maybe need ajust for include this information (if exist in the project) into `SPIRV-Tools.pc.in` and setup in the `CMakeFiles.txt`.
  - (*)The visiblility of the shared/static modules is untouched. BUT the `libSPIRV-Tools.so` (static `libSPIRV-Tools.a` is always visible) is turn to visible. needs a internal rework (point 4). i can't link with any library (tested with GLSLANG or VKD3D). Always fails to link about missing symbols.
    Needs fix by dev.

TODO:
  - Fix point (2) and point (3)

- Point (4) is out of my scope. i'm not coder
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants