I'm trying to create a small application that will be able to communicate with the AWS IoT service. Since I want it to be fairly small and I wanted to try something new, I decided to go for Kotlin Native. I quickly noticed that AWS has released their C++ library that allows you to easily connect to the AWS IoT service (https://github.com/aws/aws-iot-device-sdk-cpp/tree/release) I downloaded it and even managed to compile with MinGW (yes, I'm on Windows). I noticed that it generated a bunch of *.o files. I reckon this is now the right time to import it to my Kotlin Native project. My build.gradle file for now looks completely standard
plugins {
id 'kotlin-multiplatform' version '1.3.11'
}
repositories {
mavenCentral()
}
kotlin {
targets {
// For ARM, preset should be changed to presets.iosArm32 or presets.iosArm64
// For Linux, preset should be changed to e.g. presets.linuxX64
// For MacOS, preset should be changed to e.g. presets.macosX64
fromPreset(presets.mingwX64, 'mingw')
configure([mingw]) {
// Comment to generate Kotlin/Native library (KLIB) instead of executable file:
compilations.main.outputKinds('EXECUTABLE')
// Change to specify fully qualified name of your application's entry point:
compilations.main.entryPoint = 'sample.main'
}
}
sourceSets {
// Note: To enable common source sets please comment out 'kotlin.import.noCommonSourceSets' property
// in gradle.properties file and re-import your project in IDE.
mingwMain {
}
mingwTest {
}
}
}
task runProgram {
def buildType = 'release' // Change to 'debug' to run application with debug symbols.
dependsOn "link${buildType.capitalize()}ExecutableMingw"
doLast {
def programFile = kotlin.targets.mingw.compilations.main.getBinary('EXECUTABLE', buildType)
exec {
executable programFile
args ''
}
}
}
for some reason I cannot find any examples as to how to add my freshly complied dependency. Normally when you code C++ you have to specify the path to Include directory and the Lib directory separately. AFAIK this is not something that gradle provides out of the box. How can I import this dependency then? Or perhaps there's some centralised repository I could simply pull such dependency from, like in pretty much every other programming language that is still used nowadays? At least this specific library doesn't seem to be available on NuGet :/
Kotlin/Native is not[1] interoperable with C++ at this moment. You can however create C wrapper for any C++ library and it's functions from Kotlin/Native[2].
When using multiplatform gradle plugin you can define native interop with this syntax:
kotlin {
linuxX64 { // Replace with a target you need.
compilations.main {
cinterops {
myInterop {
// Def-file describing the native API.
// The default path is src/nativeInterop/cinterop/<interop-name>.def
defFile project.file("def-file.def")
// Package to place the Kotlin API generated.
packageName 'org.sample'
// Options to be passed to compiler by cinterop tool.
compilerOpts '-Ipath/to/headers'
// Directories for header search (an analogue of the -I<path> compiler option).
includeDirs.allHeaders("path1", "path2")
// Additional directories to search headers listed in the 'headerFilter' def-file option.
// -headerFilterAdditionalSearchPrefix command line option analogue.
includeDirs.headerFilterOnly("path1", "path2")
// A shortcut for includeDirs.allHeaders.
includeDirs("include/directory", "another/directory")
}
anotherInterop { /* ... */ }
}
}
}
}
If you only define the interop name the plugin will look for .def file[3] in src/nativeInterop/cinterop/ directory and use it (in this case src/nativeInterop/cinterop/myInterop.def).
kotlin {
linuxX64 {
compilations.main {
cinterops {
myInterop {
}
}
}
}
}
The .def files[3] contains information about the library you are trying to use and typically look like this.
headers = png.h
headerFilter = png.h
package = png
More information about cinterop: https://kotlinlang.org/docs/reference/native/c_interop.html
More information about multiplatform projects: https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html
Related
I have quite a complex project with many build variants and custom source sets. I have recently integrated the NDK and noticed something strange. Nothing is broken, everything seems to be working as it should. I'm thinking its a bug with Android Studio, unless something is wrong in the gradle config.
I added the following to my app/build.gradle
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
ndkVersion "22.0.6917172"
I then noticed that the directories within the "Project" pane of Android Studio were then displaying as if they were packages. It also looked as if every variant was being processed as well even though I am setting to be ignored.
This is what the directories looked like before
And this is what they look like now
The bigger issue is that custom source sets for build variants were being included at the app/src/ level with just the kotlin directory?
These are configured in the app/build.gradle like this example.
android {
...
sourceSets {
padoq.java.srcDirs += "src/standardTileHandler/kotlin"
}
...
}
padoq.java.srcDirs += nonHsdSource
Before, in project view, these appeared as the directory name with the packages inside, not with the kotlin directory at the root. Here is what it looked like before:
For completeness, I am ignoring certain build variants by setting the variant to be ignored in the root build.gradle's subprojects block:
subprojects {
afterEvaluate { project ->
if (project.hasProperty("android")) {
def androidProperty = project["android"]
if (androidProperty.hasProperty("flavorDimensionList")) {
def flavorDimensions = androidProperty["flavorDimensionList"]
if (flavorDimensions != null && flavorDimensions.contains("bopad")) {
androidProperty.invokeMethod("variantFilter", { variant ->
def names = variant.flavors*.name
// if names does not contain a variant that I want to build right now
setIgnore(true)
})
}
}
}
}
}
I'm currently a few days into setting up my mixed java/cpp multi-module gradle project. While I admit being new to groovy &Co, it seems every step of the way I need to find an exact example of what I'm trying to do, otherwise I cannot progress.
Q: Please can anyone tell me how to read this Gradle DSL page? I'm trying to make my library compile as static-only (not shared) and even though I have used baseName and see static and shared properties documented on the page, I can't for the life of me understand how to use them. My code is:
components {
api(NativeLibrarySpec) {
sources {
cpp {
source {
srcDir "src/main/stuff"
include "**/*.cpp"
}
}
}
baseName "mylibrary"
static "true" <-- what to write here??
shared "false" <-- ??
}
}
I took a look around and it seems that you should try that :
components {
api(NativeLibrarySpec) {
sources {
cpp {
source {
srcDir "src/main/stuff"
include "**/*.cpp"
}
}
}
binaries {
all {
lib library: "mylibrary", linkage: "static"
}
}
}
}
edit :
all is a method from the ModelMap interface, returned by the getBinaries method. It says : Applies the given action to each item in the collection
ModelMap uses BinarySpec as parameter so the parameter of all is an Action<BinarySpec> object.
So the Action class (functional interface) defines one method execute(BinarySpec spec). The method lib is from NativeBinarySpec
void lib(Object library)
Adds a library as input to this binary.
This method accepts the following types:
A NativeLibrarySpec
A NativeDependencySet
A Map containing the library selector.
The Map notation supports the following String attributes:
project: the path to the project containing the library (optional, defaults to current project)
library: the name of the library (required)
linkage: the library linkage required ['shared'/'static'] (optional, defaults to 'shared')
So, to sum things up, mylibrary is added as input to all binaries.
I created a plugin XYZ that must inject configuration in all projects (from the root).
My project is a native C++ project for Visual Studio. Hence Java dependencies are not available...
Here is my layout, both variant uses the common lib projLib. projVariant1 uses the plugin but projVariant2 does not.
myRoot
- projLib
- projVariant1 <- uses the plugin
- projVariant2
Build projVariant1 should produce: myRoot#XYZ, projLib#XYZ, projVariant1#XYZ
Build projVariant2 should produce: myRoot, projLib, projVariant2
My idea is to do something like this (pseudo code) :
def applyPluginXYZ(Project p) {
p.if_part_of_compilation { // <-- this does not exist
p.rootProject.subprojects {
// apply change
}
}
}
projVariant1's build.gradle :
apply plugin: 'cpp'
applyPluginXYZ(project)
I've been trying to figure out a proper way of leveraging the information already present in a solution file of a rather big c++ code base.
The problem I'm trying to solve is calling an external script on some of the project files within the solution, but observing the already present dependencies specified in the solution and single project files.
I've successfully called said (python) script by adding a custom target to one of my project files and using msbuild with the /t:{TargetName} command on the vcxproj file.
I could now add this target to every project file that needs to call this script and afterwards call msbuild for each of them in the correct order, however this defeats the purpose of leveraging the dependencies known by the solution.
Calling the solution with the custom target does however not work (as seen by other stackoverflow questions like this: Invoke Custom MSBuild Target on Solution File).
On the other hand, since I want to be able to ONLY call the script target and not being dependent on also calling some Build command, I cannot use the proposed workarounds in some of those answers of adding a Post or PreBuild target.
Is there any other way of using the dependencies without having to go the route of msbuild and custom targets, or is there an other workaround that could serve my purpose?
Is there any other way of using the dependencies without having to go the route of msbuild and custom targets, or is there an other workaround that could serve my purpose?
You can build the sln programmatically, Here is a console APP with c# for your reference.
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
using Microsoft.Build.Logging;
using System;
namespace LoadAllProject
{
class Program
{
static void Main(string[] args)
{
ILogger logger = new ConsoleLogger();
string solutionPath = #"D:\Project\Msbuild\CppApp5\CppApp5.sln";
var solutionFile = SolutionFile.Parse(solutionPath);
foreach (var item in solutionFile.ProjectsInOrder)
{
Project project = ProjectCollection.GlobalProjectCollection.LoadProject(item.AbsolutePath);
project.SetGlobalProperty("Configuration", "Debug");
if (project.GetPropertyValue("RootNamespace") == "CppApp5")
{
project.Build(new[] { "Build", "Yourcustomtarget" }, new[] { logger });
}
else
{
project.Build(new[] { "Build" }, new[] { logger });
}
}
Console.ReadKey();
}
}
}
I have set up a project on top of Qt (so source is written in C++) and I wanted to try Gradle for automatic builds on that. It took me some time to get into the details of configuring a multi project build (there is an executable and two libs) and now I am trying to tell the cpp-exe and the cpp-lib plugin how my source tree is structured.
I have set up a task that should print all of the source sets (there should be at least the default ones right?) and it looks like this:
task projectinfo {
description = "Informations about the current project"
group = INFORMATIONS_GROUP
doFirst {
task -> print ("""${task.project.sourceSets.all}""")
}
If I run this task Gradle tells me that there is no property "sourceSets" for the project. The documentation of the plugin tells me that it is possible to customize the source locations, but not how.
So my question would be: How can I tell the Gradle cpp plugin which source files to use. If there is any documentation about the cpp plugin apart from its API documentation and the Gradle user guide that would be helping too.
Have a look at Adam Murdoch's usage of Gradle's 'cpp plugin'. I believe he's one of the main Gradle submitters, so he should know how to use this better than anyone:
Exert from native-platform/build.gradle
cpp {
sourceSets {
main {
source.exclude 'curses.cpp'
}
curses {
source.srcDirs = ['src/main/cpp']
source.include 'curses.cpp'
source.include 'generic.cpp'
source.include 'generic_posix.cpp'
}
}
}
Then, within the 'libraries' node, refer to all/any combination of architecture and source sets:
sourceSets << cpp.sourceSets.main
sourceSets << cpp.sourceSets.curses
I've not had too long to look over it myself, but it looks like he defines a number of OS architecture based source code include combinations and stores these in the variants variable. He then processes them into platform JARs (I haven't actually ran the build yet, maybe I should).
Also, take a look at https://github.com/rklaren/GradleJNI, it uses the cpp plugin but looks to be a little Windows-oriented.
Update - I also found https://github.com/alkemist/gradle-cpp-demo, which has an example of the 'cpp-exe' plugin building an executable.