Using and deriving from interfaces defined in another COM library - com

I have two C++ COM projects in Visual Studio. In ProjectA I define InterfaceA in MIDL. In ProjectB I would like to define InterfaceB which inherits from InterfaceA. Is this possible to do without importing IDL or H files from ProjectA?
Here's how the code is laid out, which might be clearer. The libraries are large so I put things in separate files to make it easier to maintain.
Project A
InterfaceA.idl
import "oaidl.idl";
import "ocidl.idl";
[ uuid( ... ) ]
interface InterfaceA : IDispatch { ... }
CoclassA.idl
import "InterfaceA.idl";
[ uuid( ... ) ]
interface CoclassA
{
[default] interface InterfaceA;
};
ProjectA.idl
import "InterfaceA.idl";
[ uuid( ... ) ]
library ProjectA
{
interface InterfaceA;
#include "CoclassA.idl"
}
Project B
InterfaceB.idl
import "oaidl.idl";
import "ocidl.idl";
// If both interfaces were in the same project, I'd just import:
//import "InterfaceA.idl";
// Without the import I get a compilation error, obviously. I don't want to
// add ProjectA as an additional include directory because I don't want ProjectB
// to be dependent on how ProjectA's files are organized. I just want the types
// from ProjectA to be available here.
[ uuid(...) ]
interface InterfaceB: InterfaceA { ... }
CoclassB.idl
import "InterfaceB.idl";
[ uuid( ... ) ]
interface CoclassB
{
[default] interface InterfaceB;
};
ProjectB.idl
import "InterfaceB.idl";
[ uuid( ... ) ]
library ProjectB
{
// I wish using importlib would help here, but it won't since InterfaceB is
// defined and compiled by MIDL separately in InterfaceB.idl.
//importlib("ProjectA.tlb");
// I could try to #include "InterfaceB.idl", but then I would lose the
// automatic dependency analysis that MIDL does. I am also having trouble
// getting the MIDL compiler to understand #defines.
interface InterfaceB;
#include "CoclassB.idl"
}
I have a feeling that what I want to do is not possible. This wouldn't be a problem if MIDL supported an importlib equivalent outside of libraries!

Related

Include a module as a dependency into a KMM project's shared module

I have a working KMM application, and I have a java module, mymodule, that I created with File->New->Module->Java or Kotlin library.
The module exists at the top level beside androidApp, iosApp and shared. In my settings.gradle.kts I have include(":mymodule").
I want to use mymodule in the shared module. So I go into the shared module's build.gradle.kts and I try to include my module in commonMain:
kotlin {
...
sourceSets {
val commonMain by getting {
dependencies {
implementation(project(":mymodule"))
}
}
...
}
...
}
...
And the error is Could not resolve MyKMMApplication:mymodule:unspecified and:
Could not resolve project :mymodule.
Required by:
project :shared
Things I've tried
I can put dependencies { implementation(project(":mymodule")) } at the bottom of shared's build.gradle.kts and but still the same error appears
As to test if there's other problems, I can also import mymodule into the Android project without problems
I can include implementation("com.squareup.sqldelight:runtime:1.5.3") in commonMain and see those classes in the shared module no problem
The docs say you can include another multiplatform module, but nothing about a normal module.
How can I include a modules into KMM's shared module as a dependency?
So, the module you include into shared needs to be a multiplatform module. It's build.gradle.kts file should look something like this:
plugins {
id("org.jetbrains.kotlin.multiplatform")
}
kotlin {
jvm()
iosX64()
iosArm32()
iosArm64()
}
And it's project structure should look something like: mymodule/src/commonMain/kotlin/com/example/mymodule/.

Conditional compilation in rollup

How can I exclude some part of code in file (not the file itself but only few lines) from compiling into bundle? In C# it looks like
#ifdef _DEBUG
...
#else
...
#endif
Is it possible for js files compiling with rollup?
rollup-plugin-jscc
Possibly you need rollup-plugin-jscc, but I'm not sure about it's state in 2022 :(
In usage section of linked README.md file you can find example:
/*#if _DEBUG
import mylib from 'mylib-debug';
//#else */
import mylib from 'mylib'
//#endif
mylib.log('Starting $_APPNAME v$_VERSION...')
#rollup/plugin-alias
Another solution is a little bit different:
/*START.DEBUG_ONLY*/
import 'robot3/debug';
/*END.DEBUG_ONLY*/
import {...} from 'robot3';
Also you can use official #rollup/plugin-alias to mock import 'robot3/debug', but this approach needs empty mock-file for replacement, what is not so clean.
rollup.config.js
import alias from '#rollup/plugin-alias';
module.exports = {
input: ...,
output: ...,
plugins: [
...,
alias({
entries: [
{ find: 'robot3/debug', replacement: resolve(__dirname, './src/mocks/empty.js') },
]
})
]
};

Serialize kotlin data class in gradle's buildSrc/ during build

I'm looking to produce json files during the build cycle of my kotlin gradle app. My intent is to be able to instantiate data classes with a combination of public and private app configuration values that get put into the build's resources directory.
I'm looking at kotlinx.serialization, and I'd like to define these classes ideally in the projet's buildSrc/.
I haven't found any resources online for trying to setup serialization within gradle's build process, and not just configuring it for the app at runtime. This is what I've put together as my buildSrc/build.gradle.kts
plugins {
`kotlin-dsl`
kotlin("plugin.serialization") version "1.3.72"
}
repositories {
jcenter()
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0")
}
And this is my test data class:
#Serializable
data class JsonGenerator(val x: String = "")
The error I get is:
Cannot access 'Serializable': it is internal in 'kotlin.io'
It seems that this error can happen when the dependency isn't properly declared. But I'm still unclear whether buildSrc has restrictions that make this impossible or not. I'm not married to this approach, but this seemed like the best solution.
Edit:
I've changed my buildSrc/build.gradle.kts to:
plugins {
`kotlin-dsl`
}
repositories {
jcenter()
}
dependencies {
implementation(kotlin("serialization"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1")
}
Structure:
buildSrc
main
Kotlin
MyTempClass.kt
It is important for the kt file to not be nested, I think that will only work if the file is the same name as the nesting directory
Inside of my data class file:
import kotlinx.serialization.*
#Serializable
data class MyTempClass(val name: String)
I had a specific implementation of serialization, without the plugin.
Then in the top level build.gradle.kts, the MyTempClass was accessible

Unable to resolve cinterop IOS import in Kotlin Multiplatform

I have followed the Kotlin documentation for adding iOS dependencies. In my case the dependency is a pre-compiled framework provided through a third party. So I have followed the case for framework without cocoapod.
I placed my MyFramework.def file in /src
language = Objective-C
modules = MyFramework
package = MyFramework
Then I added the following to the build.gradle.kts in the Kotlin object
```
ios {
binaries {
framework {
baseName = "shared"
}
}
}
iosArm64() {
compilations.getByName("main") {
val JWBLe by cinterops.creating {
// Path to .def file
defFile("src/nativeInterop/cinterop/MyFramework.def")
compilerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
}
}
binaries.all {
// Tell the linker where the framework is located.
linkerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
}
}
sourceSets {
val commonMain by getting
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val androidMain by getting {
dependencies {
implementation("com.google.android.material:material:1.2.1")
}
}
val androidTest by getting {
dependencies {
implementation(kotlin("test-junit"))
implementation("junit:junit:4.13")
}
}
val iosMain by getting
val iosTest by getting
}
Then I build the project. The library does indeed get seen and I see that in External Libraries, there is a shared-cinterop-MyFramework.klib
However, when I try to import this package into my code under src/iosMain/kotlin/com.example.testapp.shared/platform.kt
I get unresolved error for the library. It seems like I should also need to add something to sourceSets? But I am unsure.
First of all, I got to notice that the Gradle script is incorrect. In this case, the iosArm64 target was declared twice - by the target shortcut and once again where you configure the cinterop. To avoid this duplication, it would be better to configure cinterop like that:
ios()
val iosArm = targets.getByName("iosArm64") as org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
// A bit dirty cast, but as I'm sure iosArm64 is the Native target, it should be fine. Needed to make highlighting below work as expected.
iosArm.apply {
compilations.getByName("main") {
val JWBLe by cinterops.creating {
// Path to .def file
defFile("src/nativeInterop/cinterop/MyFramework.def")
compilerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
}
}
binaries.all {
// Tell the linker where the framework is located.
linkerOpts("-framework", "MyFramework", "-F/Users/user/Projects/MyFramework/ios/SDK")
}
}
However, this adjustment won't help with accessing cinterop bindings from the iosMain. In the current state of commonizer, it can share only platform libraries. So anyway, moving all code utilizing those bindings into the src/iosArm64Main folder is the best option available at the moment. Here go an issue from the official tracker to upvote and subscribe - Support commonization of user-defined libraries.
So after some playing around I found the answer.
The dependency was set for a module of iosArm64 which is not available to the iosMain.
I created another folder src/iosArm64Main and placed the source file there. At that point it was able to resolve the library.

Setting up gradle and project structure for Kotlin Multiplatform project

I want to build a CLI tool with Kotlin Multiplatform which runs on Linux, Macos and Windows.
But I am struggling with setting up my build.gradle and my project structure. I am using IntelliJ IDEA 2020.1 and created my basic project with File -> New -> Project -> Kotlin / Native | Gradle
Currently I am looking through guides from kotlinlang.org but I am more falling then achieving something.
So far my build.gradle looks as follows:
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.72'
}
repositories {
mavenCentral()
}
kotlin {
// For ARM, should be changed to iosArm32 or iosArm64
// For Linux, should be changed to e.g. linuxX64
// For MacOS, should be changed to e.g. macosX64
// For Windows, should be changed to e.g. mingwX64
linuxX64("linux") {
}
mingwX64("mingw") {
}
macosX64("macos") {
binaries {
executable {
// Change to specify fully qualified name of your application's entry point:
entryPoint = 'sample.main'
// Specify command-line arguments, if necessary:
runTask?.args('')
}
}
}
sourceSets {
commonMain {
kotlin.srcDir('src/main')
resources.srcDir('src/res')
dependencies {
implementation kotlin('stdlib-common')
implementation "com.github.ajalt:clikt-multiplatform:2.7.0"
}
}
commonTest {
dependencies {
implementation kotlin('test-common')
implementation kotlin('test-annotations-common')
}
}
macosX64().compilations.test.defaultSourceSet {
dependsOn commonMain
}
// Note: To enable common source sets please comment out
'kotlin.import.noCommonSourceSets' property
// in gradle.properties file and re-import your project in IDE.
macosMain {
}
macosTest {
}
}
}
wrapper {
gradleVersion = "6.4.1"
distributionType = "ALL"
}
And my project structure is still basic:
Project structure
Formerly I only worked on Android Projects with Kotlin, and I guess I am spoiled with gradle as Android generates the most basic stuff and everything is working without doing that much.
I understand that I need to create packages like linuxMain and mingwMain, but where to I put common sourcesets? I tried to create a package called commonMain, but it won't even let me create Kotlin files in that package.
When I am finished I want to have (in the best case) one common source set and one entry point for all my targets. Is this even possible?
As far as I can see, you specify your commonMain source set's source locations as /src/main/. By default, it's usually set onto /src/commonMain/kotlin/. So if you will remove those srcDir settings and create a .kt file in your /src/commonMain/kotlin/ folder, everything should work fine. Also, I hope you have removed 'kotlin.import.noCommonSourceSets' property from your gradle.properties as your script recommended.