gradle / gradle-native

The home of Gradle's support for natively compiled languages
https://blog.gradle.org/introducing-the-new-cpp-plugins
Apache License 2.0
92 stars 8 forks source link

Static library: Support for both statically and dynamically linked C++ runtime #106

Open zosrothko opened 7 years ago

zosrothko commented 7 years ago

Hi

Unless I am missing something, one cannot specify to build a StaticLibraryBinarySpec linking the C++ runtime as a shared library or linking the C++ runtime as a static library. For Windows, Here the compiler flags to set for VisualStudio

As use case, both Poco and Boost are providing this feature (both in building from source or as a packaged product)

lacasseio commented 7 years ago

Thanks for opening this issue @zosrothko. Could you clarify what you mean by "cannot specify"? You can pass the compiler flag directly at the binary level. If you need are talking about mixing the dependency, unfortunately, variant needs to match each other. For example, linking debug with release variant isn't easily achievable.

zosrothko commented 7 years ago

On Poco for example, the static libraries are coming with 2 link modes (or variant?) together with release/debug variants

  1. static link with /MD that goes into Poco/lib as for example : Poco/lib/PocoCppParserMD.lib
  2. static link with /MDd that goes into Poco/lib as for example: Poco/lib/PocoCppParserMDd.lib
  3. static link with /MT that goes into Poco/lib as for example : Poco/lib/PocoCppParserMT.lib
  4. static link with /MTd that goes into Poco/lib as for example: Poco/lib/PocoCppParserMTd.lib

Thus, it seems to me there no way to have both. With a compiler flag, one can get either the MD one, either the MT one.

lacasseio commented 7 years ago

Right, in this case, you want to create an additional variant of your binaries. On the top of my head, you can either use flavors, platform or build type to map a new variant and use extended properties to register some modeling information around this linkage type. Since this is windows specific, I would use a second set of Windows platform definition that explicitly model MD vs MT, like:

platforms {
  winMD {
    operatingSystem 'windows'
    ext.isMD = { true }
  }
  winMT {
    operatingSystem 'windows'
    ext.isMD = { false }
  }
}

// later you can use
binaries.all {
  if (targetPlatform.operatingSystem.windows && targetPlatform.isMD()) {
    // ...
  }
}

A deeper model can be created. It really depends on how it's used.

zosrothko commented 7 years ago

OK that's a solution which seems more a workaround . It will overbloat the top level build.gradle script with multiple platforms definition. There will be

platforms {
     win32MD
     win32MT
     win64MD
     win64MT
}
...
targetPlatform "win32MD"
targetPlatform "win32MT"
targetPlatform "win64MD"
targetPlatform "win64MT"

which will double the overall build time.

I would have prefered an integrated solution by adding the specification of a StaticDynLibraryBinarySpec so the script could be


binary {
    withType(StaticLibraryBinarySpec) { // static library with static runtime
              cppCompiler.args "/MT"
        }
    withType(StaticDynLibraryBinarySpec) { static library with dynamic runtime
               cppCompiler.args "/MD"
        }
}