5 ms·
Didn't see one of the IMO biggest downsides of static linking in that list, which is that there is no sane way to prevent symbol clashes if different components
by w0utert 6y ago
Didn't see one of the IMO biggest downsides of static linking in that list, which is that there is no sane way to prevent symbol clashes if different components of your application need different versions of the same dependency.
When using shared linking dynamic libraries can link some of their dependencies statically into the .so, using strictly local symbols, allowing the application to load it even if it already links some other version of the same dependency.
We had this problem at my workplace where we developed a component that needed to embed a relatively modern version of the Lua interpreter. When the team that developed the application that used our component tried to link it, they found out that some ancient component they also had been linking in for some completely different and unrelated purpose had a transitive dependency on Lua 5.0, released almost 20 years ago. For backwards compatibility reasons it was not an option to modify the old component to use the newer Lua version, and linking both Lua versions statically into the same binary is impossible. This would never have been a problem if we could have shipped our component as a shared library (which we already build and use for other internal applications), because there the Lua interpreter could have been linked into the shared library privately.
- Joker_vD 6y agoUm, there is this thing called objcopy: --redefine-sym old=new Change the name of a symbol old, to new. This can be useful when one is trying link two things together for which you have no source, and there are name collisions. --redefine-syms=filename Apply --redefine-sym to each symbol pair "old new" listed in the file filename. filename is simply a flat file, with one symbol pair per line. Line comments may be introduced by the hash character. This option may be given more than once. So it's absolutely possible, just ugly.
- w0utert 6y agoI’m not sure I understand how this would help? When linking the main application there will be two component .a files linked into it, that both contain references to symbols that should be resolved to something in a liblua.a, so that needs to be linked along as well, but one component needs to resolve them to liblua.a from Lua 5.2, the other to liblua.a from 5.0. Most (but not all) of the Lua symbols from both versions have the same names. How can objcopy resolve this? Multi-pass linking or something like that?
- Joker_vD 6y agoYou rename things in liblua.a from version 5.0. to something different (append __5.0 to names or something), then in the .a file that should link to version 5.0, you rename all missing Lua symbols too. Then you link all this together: main.o component_for_lua5.0.a (modified: referenced Lua symbols renamed) component_for_lua5.2.a (with symbols left intact) liblua.a (from version 5.0, modified: symbols renamed) liblua.a (from version 5.2, its symbols left intact) There should be no more name collisions.
- w0utert 6y agoAha got it, thanks! Like you said it’s not pretty but it works, and somewhat better than the abomination they came up with instead, which involved building only the minimal part that depended on the new Lua 5.2 as shared library, then making fake shared libraries for all remaining unsatisfied symbols referenced from it to trick the linker, and compiling them in statically instead like they used to do before. Hard to explain, don’t ask me why they did it... :-/ Edit: there is one pretty glaring downside to this approach though, which is that both the component we need to patch up with renamed symbols and the liblua.a are also used in other places, so they would either have to be built differently depending on the application, or we would have to maintain multiple versions of the same 5.0 liblua.a and change the build config/detect logic, for even more confusion and ugliness >_<
- Joker_vD 6y agoIntroduce the project- nay, the organization-wide mangling scheme! Every symbol is now required to have the library's version name in its name, may as well throw in some namespaces there too. Then maintain some sort of metainfo of what part is requiring what versions, and what project is providing what versions, and... and well, at this stage you're kinda reinventing the package management, but at least you don't need a custom linker, which is a good thing, right?
- w0utert 6y agoThe not-so-funny part is that it would probably be about the same effort to do that compared to convincing everybody to use shared linking for these kinds of things >_<
- jcelerier 6y ago> Didn't see one of the IMO biggest downsides of static linking in that list, which is that there is no sane way to prevent symbol clashes if different components of your application need different versions of the same dependency. wouldn't symbol versioning allow to do something like this ? it needs a bit of modification of the Lua sources but that can likely be quickly automated with some bash script annotate lua 5 functions definitions to look like __attribute__ ((__symver__ ("lua_func@VERS_50"))) void lua_func_v50() { ... } annotate lua 5.1 functions likewise __attribute__ ((__symver__ ("lua_func@VERS_51"))) void lua_func_v51() { ... } and then in the files which uses Lua 5 put at top level : asm (".symver lua_func, lua_func@VERS_50"); and conversely VERS_51 for lua 5.1 - now that .o file should resolve to lua_func_v50 or lua_func_v51 when lua_func is called