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

Support a cross-platform symbol export list for library targets #4298

Open
haasn opened this issue Sep 30, 2018 · 6 comments
Open

Support a cross-platform symbol export list for library targets #4298

haasn opened this issue Sep 30, 2018 · 6 comments

Comments

@haasn
Copy link
Contributor

haasn commented Sep 30, 2018

To control symbol visibility, the FAQ suggests hard-coding -Wl,--version-script,foo.map with foo.map being a GCC linker script. However, this approach is not portable to various other compilers. It will not easily work on windows, macOS, etc.

Instead of having projects hard-code stuff like this, I think it would be a good idea for meson to take care of symbol visibility in a cross-platform way. I suggest adding an extra parameter to the library() targets, like symbols: or whatever, which takes a list of symbols to export. (Or a path to a file or whatever)

Some hints for how to use this symbol list on various platforms can be taken from waflib/extras/syms.py:

#! /usr/bin/env python
# encoding: utf-8
# Original source: waflib/extras/syms.py from waf git 610d0d59f (New BSD License)

"""
set the list of symbols exported from a dynamic library
to use the tool, do something like:

def build(ctx):
        ctx(features='c cshlib syms', source='a.c b.c', export_symbols_def='syms.def', target='testlib')

only the symbols listed in the file syms.def will be exported.
"""

from waflib.Context import STDOUT
from waflib.Task import Task
from waflib.Errors import WafError
from waflib.TaskGen import feature, after_method

class compile_sym(Task):
    def run(self):
        lsyms = []
        for line in self.inputs[0].read().split():
            lsyms.append(line.strip())
        lsyms.sort()
        if self.env.DEST_BINFMT == 'pe':
            self.outputs[0].write('EXPORTS\n' + '\n'.join(lsyms))
        elif self.env.DEST_BINFMT == 'elf':
            self.outputs[0].write('{ global:\n' + ';\n'.join(lsyms) + ";\nlocal: *; };\n")
        elif self.env.DEST_BINFMT == 'mac-o':
            self.outputs[0].write('\n'.join("_"+sym for sym in lsyms) + '\n')
        else:
            raise WafError('NotImplemented')

@feature('syms')
@after_method('process_source', 'process_use', 'apply_link', 'process_uselib_local', 'propagate_uselib_vars')
def do_the_symbol_stuff(self):
    tsk = self.create_task('compile_sym',
    [self.path.find_node(self.export_symbols_def)],
    self.path.find_or_declare(getattr(self, 'sym_filename', self.target + '.def')))
    self.link_task.set_run_after(tsk)
    self.link_task.dep_nodes.append(tsk.outputs[0])
    if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME):
        self.link_task.env.append_value('LINKFLAGS', ['/def:' + tsk.outputs[0].bldpath()])
    elif self.env.DEST_BINFMT == 'pe': #gcc on windows takes *.def as an additional input
        self.link_task.inputs.append(tsk.outputs[0])
    elif self.env.DEST_BINFMT == 'elf':
        self.link_task.env.append_value('LINKFLAGS', ['-Wl,-version-script', '-Wl,' + tsk.outputs[0].bldpath()])
    elif self.env.DEST_BINFMT == 'mac-o':
        self.link_task.env.append_value('LINKFLAGS', ['-exported_symbols_list', tsk.outputs[0].bldpath()])
    else:
        raise WafError('NotImplemented')
@haasn
Copy link
Contributor Author

haasn commented Sep 30, 2018

I suggest adding an extra parameter to the library() targets, like symbols: or whatever, which takes a list of symbols to export. (Or a path to a file or whatever)

Maybe for convenience we could have a parameter symbols and a parameter symbols_file pointing to a file containing the symbols (one per line), the logical union of which will be exported.

@jpakkane
Copy link
Member

jpakkane commented Oct 2, 2018

It should be noted that the recommended and portable way of controlling symbol visibility is visibility attributes. If it is in any way possible to use (or port to) those, you really should. It also makes it possible for the compiler to do extra optimizations.

@haasn
Copy link
Contributor Author

haasn commented Oct 2, 2018

@jpakkane One of the issues I have with the visbility attributes is that they don't appear to allow hiding symbols re-exported by static includes.

For a concrete example, this build script sets -fvisibility=hidden for both C and C++, but all of glslang's symbols are still contained in the resulting .so.

Do you know of a way around that without relying on a linker script?

@nirbheek
Copy link
Member

nirbheek commented Oct 2, 2018

I believe the way to do that is -Wl,--exclude-libs=ALL. That will exclude symbols from all static libraries linked into the shared library.

@ePirat
Copy link
Contributor

ePirat commented Oct 5, 2018

I believe the way to do that is -Wl,--exclude-libs=ALL.

Thats not portable, it does not work with the macOS linker for example. And even if it would I guess it would not help with object files that are built by generators like nasm where the generator tool does not support symbol visibility.

So I believe there is a need for a portable way to specify a symbol export list in meson, like it can be done for libtool.

@nickbroon
Copy link

A possible duplicate of #3047?
For which there appears to be a WIP PR at #4747

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

No branches or pull requests

5 participants