How to determine linkerOpts at build-time?

I have a Kotlin multiplatform project where I link with ICU. To make that work, I have created the following .def file:

headers = unicode/ustring.h unicode/utf8.h unicode/uchar.h unicode/ucnv.h unicode/ubrk.h
headerFilter = unicode/*

compilerOpts.linux = -I/usr/include -I/usr/include/x86_64-linux-gnu
linkerOpts.osx = -licui18n -licuuc -licudata
linkerOpts.linux = -L/usr/lib64 -licui18n -licuuc -licudata

This works fine on my Fedora system, but when building on Ubuntu this fails because linkerOpts.linux is wrong. I need to change the link path to: /usr/lib/x86_64-linux-gnu.

This leads me to two questions:

  1. Why do I have to specify the link path in the first place? Normally this is determined automatically, and different distributions use different paths. In fact, it’s impossible to predict which ones are needed.
  2. Assuming there are some technical reasons why the link path can’t be set up automatically, how can I add some code that runs during build that computes this path automatically? Basically, I’d need to call out to some code that looks at ld.so.conf to determine which path should be used.

What is the proper way to solve this problem?

You can either,

  1. Not specify a link path and leave consumers of you library to specify it themselves, since they know their system.
  2. List all paths you’re currently aware in the link line.

Relevant issue here https://github.com/JetBrains/kotlin-native/issues/1534 .

Thank you. I decided to add code to dynamically compute the linker options. For the regular build, this was rather easy as all I had to do was to add a linkerOpts parameter to the linuxX64.binaries.executable group.

When I do this, building the main binary works, but the tests fail because the test binary is not built with these flags. According to the documentation, I have to use linuxX64.binaries.test instead, like this:

linuxX64("linux") {
    binaries {
        executable {
            linkerOpts = ...
        }
        test {
            linkerOpts = ...
        }
    }
}

But when I do this, even if the test group is completely empty, I get the following error from Gradle:

Build file '/home/elias/prog/array_kotlin/array/build.gradle' line: 46

A problem occurred evaluating project ':array'.
> Cannot create binary debugTest: binary with such a name already exists

How can I add linker options programmatically to both the normal and test builds?

I experimented a bit more, and the only way by which I seem to be able to specify linker options to the test target seems to be the following:

linuxX64("linux") {
    compilations.test.kotlinOptions {
        freeCompilerArgs = ["-linker-options", "-L/usr/lib64 -licui18n -licuuc -licudata"]
    }
}

Is this really the only way to do this?

Hello, @Loke! I think the first approach you tried (the one with a linuxX64.binaries.test) fails because of some misunderstanding. You’re specifying a new test task here, instead of changing the old one. I suppose that using binaries.getTest(DEBUG) would make more sense here. Or, maybe even binaries.all, to avoid duplicating lines. See the details here.
The second approach seems fine, I would only recommend you to generalize it a bit - one can share this configuration between test and main compilation using compilation.forEach {...} method.