I’ve done extensive research and tryal-and-error-coding on this one, so help would be greatly appreciated.
I’m moving a large C codebase from custom scripts (no make) to gradle. So far I’ve managed to configure and build all libraries.
Now I’m stuck on two problems building the executables:
1.) One executable uses a textfile of symbol names to dynamically export as symbols. (linker Option “-E”) which has to be supplied before the -o Option and the list of object-files to link. e.g.
gcc -Wl,-E symbols.exp -o myExe.o -L libraries
2.) Unfortunately there is cyclic dependencies between the libraries sigh, so that i will have to whether supply libraries multiple times as parameters or will have to surround them by
–start-group --end-group
options.
I cannot figure out a standard way to do this, because this discussion entry seems not to work (for me/any more) and i could not find any other method myself of messing with the linker arguments. (I know it is not a standard nor pretty thing to do).
So I dug into the gradle source code a bit where i discovered GccLinkerArgsTransformer (in File GccLinker.java) which is exactly the place where I would like to start messing with in order to satisfy my requirements. Is there any way of replacing/extending that part without registering a whole new toolchain?
Of course I would be grateful for any other thoughts and hints to solve those problems (apart from getting rid of the cyclic dependencies which unfortunately seems to be a lost cause )
asking here helped me after all, though not in the way I expected (yet).
In the documentation Example 56.31. Reconfigure tool arguments there is an example of how to mess with the arguments (along with the hint that it is not a good idea compared to cleanly modeling the dependencies).
Gradle provides a hook that allows the build author to control the exact set of arguments passed to a tool chain executable. This enables the build author to work around any limitations in Gradle, or assumptions that Gradle makes. The arguments hook should be seen as a ‘last-resort’ mechanism, with preference given to truly modelling the underlying domain.
I stumbled upon that before and it did not work. In retrospective I think I missed the surounding tag:
model {
}
So my current (ugly and very brittle) solution to the above stated problems looks like this:
model {
toolChains {
gcc(Gcc) {
eachPlatform {
linker.withArguments { args ->
List origArgs = new ArrayList(args)
List newArgs = new ArrayList()
// add the symbol list to the linker if "SrvExecutable" gets linked
if (name.contains("SrvExecutable")) {
newArgs.add("-Wl,-E")
newArgs.add("$generatedSourceAbsolutePath/srvall.exp")
}
// add --start-group und --end-group in order to allow the linker to resolve circular dependencies.
boolean addStartGroup = false;
boolean startGroupAdded = false;
boolean endGroupAdded = false;
origArgs.eachWithIndex { obj, i ->
String param = obj as String
// insert ‘End a group’ after the libraries (the first argument is always "-o")
if(startGroupAdded == true
&& endGroupAdded == false
&& param.startsWith("-") ) {
newArgs.add("-Wl,--end-group")
endGroupAdded = true
}
// add parameter from original list
newArgs.add(param)
// add --start-group right after the first "-o", "<fileName>"
if (startGroupAdded == false && addStartGroup == true) {
newArgs.add("-Wl,--start-group")
startGroupAdded = true
}
if(param.equalsIgnoreCase("-o")) {
// The parameter "-o" signals that the next parameter will be the name of the outfile. Right after that follows a list of libraries.
addStartGroup = true
}
}
args.clear()
args.addAll(newArgs)
}
}
}
}
}