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

No longer possible to force-merge static libraries via link_whole #12638

Open
Akaricchi opened this issue Dec 17, 2023 · 0 comments · May be fixed by #13768
Open

No longer possible to force-merge static libraries via link_whole #12638

Akaricchi opened this issue Dec 17, 2023 · 0 comments · May be fixed by #13768

Comments

@Akaricchi
Copy link
Contributor

Akaricchi commented Dec 17, 2023

Describe the bug
It used to be possible to force creation of a "fat" internal static library by using link_whole:

lib1 = static_library('1', 'lib1.c')
dep1 = declare_dependency(link_with : lib1)

lib2 = static_library('2', 'lib2.c', dependencies : dep1)
dep2 = declare_dependency(link_with : lib2)
  
lib3 = static_library('3', 'lib3.c', dependencies : dep2)
dep3 = declare_dependency(link_with : lib3)

# libcombined should contain objects from all of the above
libcombined = static_library('combined', link_whole : lib3)

Since commit a78af23 (PR #11742), this no longer happens unless the library is also installed.

This code seems to be the culprit:

    @lru_cache(maxsize=None)
    def get_dependencies(self) -> OrderedSet[Target]:
        # Get all targets needed for linking. This includes all link_with and
        # link_whole targets, and also all dependencies of static libraries
        # recursively. The algorithm here is closely related to what we do in
        # get_internal_static_libraries(): Installed static libraries include
        # objects from all their dependencies already.
        result: OrderedSet[Target] = OrderedSet()
        for t in itertools.chain(self.link_targets, self.link_whole_targets):
            if t not in result:
                result.add(t)
                if isinstance(t, StaticLibrary):
                    t.get_dependencies_recurse(result)
        return result

To Reproduce

  1. Download and extract this contrived test case.
  2. Build it. Linking should fail due to a missing symbol.
  3. Change the install parameter to true in the meson.build. Linking should succeed after that.

Expected behavior
link_whole: true producing a "fat" static library containing objects of all of its dependencies, regardless of whether the library is going to be installed or not. Alternatively, another way to achieve the same result should be added.

Although the test case is very contrived, I have an actual use-case for this feature. For web builds of Taisei, we rely on emcc's html output mode, which is not natively supported by Meson. For that reason, we have to resort to a nasty hack that involves invoking the compiler manually via a custom_target for the linking step. It looks like this:

    # First compile our code into a regular static library.
    # This contains only Taisei objects.
    libtaisei = static_library(taisei_basename, taisei_src, version_deps,
        dependencies : taisei_deps,
        c_pch : 'pch/taisei_pch.h',
        c_args : [em_common_args, taisei_c_args],
        install : false,
    )

    # Create a "fat" static library with Taisei code + all dependencies.
    # This is very important because Meson is clueless about our custom linker invocation below,
    # thus it will be unable to resolve dependencies at that stage.
    taisei = static_library(taisei_basename + '-full',
        link_whole : libtaisei,
    )

    # abandon hope all ye who enter here
    taisei_html = custom_target(em_link_outputs[0],
        command : [
            meson.get_compiler('cpp').cmd_array(),
            taisei,
            '--pre-js', em_preamble,
            '--shell-file', em_shell,
            em_common_args,
            em_link_args,
            '-o', '@OUTPUT0@',
        ],
        build_by_default : true,
        output : em_link_outputs,
        install : true,
        install_dir : bindir,
        install_tag : 'runtime',
    )

Unfortunately, this no longer works after a78af23. I could work around it by specifying install : true and adding an install script to remove the unwanted file later, but I really don't think I should have to resort to that.

Of course, it would be awesome to have better support for Emscripten's quirks in Meson directly so I wouldn't even have to do it like this in the first place, but that honestly seems like more trouble than it's worth to maintain, as its CLI is far less stable than that of most other compilers.

Regardless, I believe there should be a sane way to create a self-contained static library that is not inexplicably tied to install.

system parameters

  • Meson a78af23; latest master also affected
Akaricchi added a commit to taisei-project/taisei that referenced this issue Jan 24, 2024
Akaricchi added a commit to taisei-project/taisei that referenced this issue Mar 3, 2024
@eerii eerii linked a pull request Oct 9, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant