Open aschneid1 opened 6 years ago
the linker has decided that your symbols are unused and optimises them out. the UNIX linker ld
has a --no-as-needed
option to disable exactly this (https://linux.die.net/man/1/ld, search for "as-needed") but that doesn't work on Windows so perhaps Premake could include a cross-platform flag?
https://stackoverflow.com/questions/14116420/how-to-force-gcc-to-link-an-unused-static-library
It looks like as-needed is specifically for dynamic libraries, while the whole-archive and force-load options work for static (although that may be wrong).
In either case, applying -Wl options to specific libraries doesn't seem possible with premake at the moment.
For what it's worth, I hacked around my problem by just specifying the object directory for each project to be the same. That way if I compile (for example) ProjectTitle, it generates all of its object files. If I then compile ProjectTitleTests, it finds object files (if using the same configuration) that were compiled by the ProjectTitle project and links those in. It's not ideal, but it works. I can just place this
objdir("!./config/build/" .. _ACTION .. "/obj/%{cfg.buildcfg}")
in each project to ensure they share the same object directory (in this case, the current directory/config/build/[vs2017,gmake,etc.]/obj/[release,debug,etc.]).
In either case, applying -Wl options to specific libraries doesn't seem possible with premake at the moment
Does this not work for your situation?
project "blah"
filter { "system:linux" }
linkoptions { "-Wl," .. option }
Not easily, but I managed -- it just wasn't pretty. We have 4 configurations: balanced, debug, profile, and release.
Targeting the correctly built library for the current configuration is finicky. I had to do something like:
function linkStaticLib()
-- A hack to be able to link StaticLib with whole-archive
-- Should ideally just be links{"StaticLib"}, then it would just...work
libdirs{"./config/build/staticlib"}
dependson{"StaticLibProject"}
-- GCC Options
filter { "toolset:gcc", "configurations:Balacned" }
linkoptions{"-Wl,--whole-archive libStaticLibBalanced.a -Wl,--no-whole-archive"}
filter { "toolset:gcc", "configurations:Release" }
linkoptions{"-Wl,--whole-archive libStaticLibRelease.a -Wl,--no-whole-archive"}
filter { "toolset:gcc", "configurations:Debug" }
linkoptions{"-Wl,--whole-archive libStaticLibDebug.a -Wl,--no-whole-archive"}
filter { "toolset:gcc", "configurations:Profile" }
linkoptions{"-Wl,--whole-archive libStaticLibProfile.a -Wl,--no-whole-archive"}
-- Clang options
filter { "toolset:clang", "configurations:Balanced" }
linkoptions{"-Wl,-force-load,libStaticLibBalanced.a"}
filter { "toolset:clang", "configurations:Release" }
linkoptions{"-Wl,-force-load,libStaticLibRelease.a"}
filter { "toolset:clang", "configurations:Debug" }
linkoptions{"-Wl,-force-load,libStaticLibDebug.a"}
filter { "toolset:clang", "configurations:Profile" }
linkoptions{"-Wl,-force-load,libStaticLibProfile.a"}
filter{}
end
That works, but it's not super clear, and isn't very maintainable. Ideally, we would have something more like linksWithOption{"StaticLib", "force-load"} that would correctly build the project StaticLib for the current configuration, link it, and wrap it in -Wl,-force-load or -Wl-whole-archive/no-whole-archive options.
To shorten your workaround, you could use tokens and have something like this
-- GCC Options
filter { "toolset:gcc" }
linkoptions{"-Wl,--whole-archive libStaticLib%{cfg.buildcfg}.a -Wl,--no-whole-archive"}
-- Clang options
filter { "toolset:clang" }
linkoptions{"-Wl,-force-load,libStaticLib%{cfg.buildcfg}.a"}
filter{}
%{cfg.buildcfg}
will be substituted with the configuration name (so Balanced, Release, etc).
Anyway, this is a workaround and we should have a proper way to do this.
I think we could expand the link mode with a :whole
which pull the lib in a whole group inside the static group (I don't think while linking is a thing for dynamic libs).
I will see if I find the time to look into it.
%{cfg.buildcfg} will be substituted with the configuration name (so Balanced, Release, etc).
Derp. Way better idea than dumping all of my obj files into the same directory (causes conflicts if files from two projects happen to have the same name).
Thanks!
probably should be -force_load
not -force-load
for Clang?
On OSX try -all_load
and -noall_load
linker options.
Hey, sorry to revive this old one. I assume this is the part of the code responsible for wrapping libs with -Bstatic ... -Bdynamic https://github.com/premake/premake-core/blob/d842e671c7bc7e09f2eeaafd199fd01e48b87ee7/src/tools/gcc.lua#L590-L591
If possible, maybe something like mylib:static_whole
would help, so later you can add
-- ...
-- ...
local static_whole_syslibs = {"-Wl,--whole-archive -Wl,-Bstatic"}
-- ...
-- ...
elseif endswith(name, ":static_whole") then
name = string.sub(name, 0, -14)
table.insert(static_whole_syslibs, "-l" .. name)
-- ...
-- ...
if #static_whole_syslibs > 1 then
table.insert(static_whole_syslibs, "-Wl,-Bdynamic -Wl,--no-whole-archive")
move(static_whole_syslibs, result)
end
I can submit a PR if that's accepted. Edit: For anyone looking for a quick and dirty solution, here's what I came up with. Just add it to the top of your .lua script
-- add "-Wl,--whole-archive -Wl,-Bstatic -lmylib -Wl,-Bdynamic -Wl,--no-whole-archive"
-- via: links { 'mylib:static_whole' }
premake.override(premake.tools.gcc, "getlinks", function(originalFn, cfg, systemonly, nogroups)
-- source:
-- premake.tools.gcc.getlinks(cfg, systemonly, nogroups)
-- https://github.com/premake/premake-core/blob/d842e671c7bc7e09f2eeaafd199fd01e48b87ee7/src/tools/gcc.lua#L568C15-L568C22
local result = originalFn(cfg, systemonly, nogroups)
local static_whole_syslibs = {"-Wl,--whole-archive -Wl,-Bstatic"}
local endswith = function(s, ptrn)
return ptrn == string.sub(s, -string.len(ptrn))
end
local idx_to_remove = {}
for idx, name in ipairs(result) do
if endswith(name, ":static_whole") then
name = string.sub(name, 0, -14)
table.insert(static_whole_syslibs, name) -- it already includes '-l'
table.insert(idx_to_remove, idx)
end
end
-- remove from the end to avoid trouble with table indexes shifting
for iii = #idx_to_remove, 1, -1 do
table.remove(result, idx_to_remove[iii])
end
local move = function(a1, a2)
local t = #a2
for i = 1, #a1 do a2[t + i] = a1[i] end
end
local new_result = {}
if #static_whole_syslibs > 1 then
table.insert(static_whole_syslibs, "-Wl,-Bdynamic -Wl,--no-whole-archive")
move(static_whole_syslibs, new_result)
end
-- https://stackoverflow.com/a/71719579
-- because of the way linux handles linking, the order on the commnadline becomes important
-- static whole libs are added first since they'll retain all symbols,
-- non-static/whole libs are appended afterwards, in case one of the static/whole libs
-- mentions one of the symbols provided later by the non-static/whole libs
-- otherwise symbols from the dynamic/non-whole libs might be removed during linking, resulting in linking failure
move(result, new_result)
return new_result
end)
Is there a way to link a static library project with "whole-archive" and the clang equivalent ("force-load")?
I have several project targets that all compile several of the same CPP files (which takes a while). If I could instead compile these common files to a static lib and link that, it would work fantastically, but unfortunately both clang and gcc remove several symbols from the static lib project. Using the whole-archive and force-load option fixes this, but there doesn't appear to be a way to link a library with these options.
The only related issue I could find was this: https://github.com/premake/premake-core/pull/662, which refers to this commit: https://github.com/premake/premake-core/pull/662/commits/2e3370e6a37b7359bf22cfd88d5664908e24b047
Am I out of luck?