@@ -166,47 +166,72 @@ Here goes all heavy lifting codegen
166166
167167#### Compiler Specific Modules
168168
169- > [ !NOTE] Has its drawbacks, maybe we'll redesign later.
170-
171169We have a problem when developing a Kotlin compiler plugin:
172170Compiler API is not stable (not won't be for a while). So how can one develop a plugin that works stably?
173171
174172We compile for multiple Kotlin versions at once!
175173
176174We use an in-house ✨technology✨ for this: CSM or Compiler Specific Modules.
177- The idea is to substitute source sets depending on the current kotlin compiler version
175+ This is a templating engine, which resolution is based on the current kotlin compiler version
178176(` kotlin-compiler ` in [ libs.versions.toml] ( ../versions-root/libs.versions.toml ) ).
179177
180- There is always a ` core ` source set (like this: [ core ] ( ../compiler-plugin/compiler-plugin-k2/src/main/core ) )
178+ There is always a core source set (like this: [ kotlin ] ( ../compiler-plugin/compiler-plugin-k2/src/main/kotlin ) )
181179that compiles nicely on all Kotlin versions. It is the majority of the code.
182- And then we have source sets that are swapped for a specific version
183- (check other directories in the [ main ] ( ../compiler-plugin/compiler-plugin-k2/src/main ) ).
180+ And then we have a template set, which is processed before compilation for a specific version.
181+ ([ templates ] ( ../compiler-plugin/compiler-plugin-k2/src/main/templates ) ).
184182
185- The code that swaps them is in [ compiler-specific-module.gradle.kts ] ( ../gradle-conventions/src/main/kotlin/compiler-specific-module.gradle.kts ) .
183+ The code that swaps them is in [ template.kt ] ( ../gradle-conventions/src/main/kotlin/util/csm/template.kt ) .
186184
187185The rules are the following:
188- - Check all source sets that start with ` v_ ` (for example, ` v_2_2 ` , ` v_2_1 ` , ` v_2_2_2 ` ).
189- It matches the most specific like a tree (so for ` 2.2.20 ` it will be ` v_2_2_2 ` , for ` 2.2.10 ` - ` v_2_2 ` and for ` 2.3.0 ` none).
190- If found one - its taken.
191- - If none, then check all that start with ` pre_ ` (for example, ` pre_2_0_10 ` , ` pre_2_1_0 ` , ` pre_2_2_0 ` ).
192- Again, it matches the most specific inclusively, but chronologically
193- (for ` 2.1.0 ` it will be ` pre_2_1_0 ` , for ` 2.0.0 ` - ` pre_2_0_10 ` , for ` 2.3.0 ` none)
194- - Take ` latest ` otherwise
195- - Suffixes don't matter (` 2.2.0 ` and ` 2.2.0-RC ` are considered the same)
196-
197- It allows supporting some past and future Kotlin versions
186+ - We enclose code dependent on a version in ` ##csm ` tags.
187+ - Every such block must:
188+ - Start with ` //##csm <block_name> `
189+ - End with ` //##csm /<block_name> `
190+ - Specify inside zero of more of the code blocks:
191+ - ` //##csm default ` + ` //##csm /default `
192+ - ` //##csm specific=[<version_patten>] ` + ` //##csm /specific `
193+
194+ Example code:
195+ ``` kotlin
196+ fun functionAvailableInAllVersions () {
197+
198+ }
199+ fun csmFunction () {
200+ // ##csm my-block
201+ // ##csm default
202+ return 1
203+ // ##csm /default
204+ // ##csm specific=[2.0.0...2.1.0, 2.1.0-ij-*]
205+ return 2
206+ // ##csm /specific
207+ // ##csm /my-block
208+ }
209+ ```
210+
211+ Templates matches ` specific ` versions greedy, so with multiple ` specific ` blocks - first one matched will be chosen,
212+ or ` default ` if none, or nothing if there is no ` default ` .
213+
214+ ` <version_pattern> ` works like this:
215+ - It's a comma-separated array of versions matchers
216+ - Version matcher is either:
217+ - Range — consists of ` from ` and ` to ` version separated by ` ... ` .
218+ ` From ` must be an exact version without a suffix.
219+ ` To ` must be a version without a suffix, where ` * ` can be used for any part: ` 2.2.* ` , ` 2.* ` but not ` 2.2.2* ` .
220+ - Prefix matcher — matches a version by prefix: ` 2.2.0-* ` , ` 2.2.2* ` , ` 2.3.0-dev-* `
221+
222+ This allows us to support some past and future Kotlin versions
198223(including versions for IDE, which are not in the stable list nor generally public) simultaneously.
199224
200- Rule for complier API breaking changes:
225+ Rules for complier API breaking changes:
201226- If some function or property changed signature or was replaced by another -
202- use ` VersionSpecificApi ` interface in ` core ` to declare functionality
203- and write the implementation in ** all** other source sets
204- (see [ FirVersionSpecificApi.kt] ( ../compiler-plugin/compiler-plugin-k2/src/main/core/kotlinx/rpc/codegen/FirVersionSpecificApi.kt )
205- and [ VersionSpecificApi.kt] ( ../compiler-plugin/compiler-plugin-backend/src/main/core/kotlinx/rpc/codegen/VersionSpecificApi.kt ) ).
227+ use ` VersionSpecificApi ` interface in core to declare functionality
228+ (see [ FirVersionSpecificApi.kt] ( ../compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/FirVersionSpecificApi.kt )
229+ and [ VersionSpecificApi.kt] ( ../compiler-plugin/compiler-plugin-backend/src/main/kotlin/kotlinx/rpc/codegen/VersionSpecificApi.kt ) ).
206230- If some class differs in signature,
207- write a proxy in ` core ` and implementation in source sets. FQ name must match exactly
208- (see [ FirRpcCheckersVS.kt] ( ../compiler-plugin/compiler-plugin-k2/src/main/v_2_3/kotlinx/rpc/codegen/checkers/FirRpcCheckersVS.kt ) )
209- as an example, and all classes with the same names in other source sets.
231+ write a proxy in core and implementation in the template.
232+ FQ name must match exactly.
233+ (see [ FirRpcCheckersVS.kt] ( ../compiler-plugin/compiler-plugin-k2/src/main/templates/kotlinx/rpc/codegen/checkers/FirRpcCheckersVS.kt )
234+ as an example)
210235
211236TeamCity is set up to work with multiple Kotlin versions for testing and releases.
212237
@@ -365,14 +390,14 @@ Here is a 'simple' guide for solving problems:
365390 - ` Cannot connect to the Docker daemon ` - open ` Docker Desktop `
366391- Kotlin/Js or Kotlin/Wasm
367392 - ` kotlinUpgradePackageLock ` or ` kotlinWasmUpgradePackageLock ` (and also ` kotlinNpmInstall ` or ` kotlinWasmNpmInstall ` )
368- have a funny tendency to fail sometimes, and you don't know why.
369- < br />
370- I'll tell you!
371- < br />
372- We use proxy repos, and sometimes dependencies get downloaded from the wrong source.
373- Make sure ALL urls in ` package-lock.json ` files start with ` https://packages.jetbrains.team/npm/p/krpc/build-deps/ ` .
374- < br />
375- If something doesn't work, your steps are:
393+ have a funny tendency to fail sometimes, and you don't know why.
394+
395+ I'll tell you!
396+
397+ We use proxy repos, and sometimes dependencies get downloaded from the wrong source.
398+ Make sure ALL urls in ` package-lock.json ` files start with ` https://packages.jetbrains.team/npm/p/krpc/build-deps/ ` .
399+
400+ If something doesn't work, your steps are:
376401 - Delete ` package-lock.json ` file
377402 - Delete ` <REPO_ROOT>/build/js ` / ` <REPO_ROOT>/build/wasm `
378403 - Run ` kotlinUpgradePackageLock ` / ` kotlinWasmUpgradePackageLock `
@@ -384,13 +409,13 @@ If something doesn't work, your steps are:
384409 - ` always-auth=true `
385410 - ` save-exact=true `
386411 - ` //packages.jetbrains.team/npm/p/krpc/build-deps/:_authToken=<your_auth_token> ` ,
387- where ` <your_auth_token> ` is from the [ proxy-repositories.md] ( proxy-repositories.md ) guide.
412+ where ` <your_auth_token> ` is from the [ proxy-repositories.md] ( proxy-repositories.md ) guide.
388413 - Check that ` <USER_HOME>/.npmrc ` / ` <USER_HOME>/.yarnrc ` don't interfere
389- command to debug. Replace versions of tools if needed.
414+ command to debug. Replace versions of tools if needed.
390415 - When you get the following error — ` puppeteer ` failed to run the installation script.
391- Reasons vary, try updating the version to a newer one,
392- check the [ .puppeteerrc.cjs] ( ../.puppeteerrc.cjs ) and [ chrome_bin.js] ( ../karma/chrome_bin.js ) files if they are valid js.
393-
416+ Reasons vary, try updating the version to a newer one,
417+ check the [ .puppeteerrc.cjs] ( ../.puppeteerrc.cjs ) and [ chrome_bin.js] ( ../karma/chrome_bin.js ) files if they are valid js.
418+
394419 For (2), check out our guide on configuring puppeteer at https://pptr.dev/guides/configuration.
395420 at ChromeLauncher.resolveExecutablePath (/rpc/build/js/packages/kotlinx-rpc-utils-test/node_modules/puppeteer-core/lib/cjs/puppeteer/node/ProductLauncher.js:295:27)
396421
@@ -410,27 +435,33 @@ check the [.puppeteerrc.cjs](../.puppeteerrc.cjs) and [chrome_bin.js](../karma/c
410435 }
411436 }
412437 This means the ` puppeteer ` failed to locate Chrome.
413- Either the cache dir is wrong (check [ .puppeteerrc.cjs] ( ../.puppeteerrc.cjs ) file) or it really isn't there.
414- <br />
415- Reasons again vary.
416- When ` npm ` installs ` puppeteer ` , it should execute script to install the browser too
417- (On CI to the ` <ROOT_DIR>/.puppeteer/browsers ` directory).
418- This absence may be caused by the ` --ignore-scripts ` flag.
419- Check the clean installation (` rm -rf build && ./gradlew clean cleanJsBrowserTest ` ) with ` --debug ` flag.
420- (Something like ` ./gradlew jsBrowserTest --debug ` ).
421- ** IMPORTANT: run in docker with ` TEAMCITY_VERSION ` env var set, if you are chasing a CI fail** .
422- <br />
423- The property is set in [ npm.kt] ( ../gradle-conventions/src/main/kotlin/util/tasks/npm.kt ) , see ` ignoreScripts ` ,
424- it should be ` false ` .
425- <br />
426- If this is not the case, check the debug log for other ` node ` -related issues.
427- Try installing browsers manually: ` ~/.gradle/nodejs/node-v22.0.0-linux-x64/bin/node build/js/node_modules/puppeteer/install.mjs `
428- If this works — problem is somewhere in KGP and probably your configs.
429- Check that your config (like ones with ` ignoreScript ` ) are actually applied,
430- as they use on demand execution and may target wrong plugin or extension and never be executed.
431- <br />
432- ** Bonus** : it may not be installed, because npm install doesn't do this.
433- See the long comment in [ npm.kt] ( ../gradle-conventions/src/main/kotlin/util/tasks/npm.kt ) .
438+ Either the cache dir is wrong (check [ .puppeteerrc.cjs] ( ../.puppeteerrc.cjs ) file) or it really isn't there.
439+
440+ Reasons again vary.
441+
442+ - When ` npm ` installs ` puppeteer ` , it should execute script to install the browser too
443+ (On CI to the ` <ROOT_DIR>/.puppeteer/browsers ` directory).
444+ This absence may be caused by the ` --ignore-scripts ` flag.
445+
446+ Check the clean installation (` rm -rf build && ./gradlew clean cleanJsBrowserTest ` ) with ` --debug ` flag.
447+ (Something like ` ./gradlew jsBrowserTest --debug ` ).
448+
449+ The property is set in [ npm.kt] ( ../gradle-conventions/src/main/kotlin/util/tasks/npm.kt ) , see ` ignoreScripts ` ,
450+ it should be ` false ` .
451+
452+ ** IMPORTANT: run in docker with ` TEAMCITY_VERSION ` env var set, if you are chasing a CI fail** .
453+
454+ - If this is not the case, check the debug log for other ` node ` -related issues.
455+ Try installing browsers manually:
456+
457+ ~ /.gradle/nodejs/node-v22.0.0-linux-x64/bin/node build/js/node_modules/puppeteer/install.mjs
458+
459+ If this works — problem is somewhere in KGP and probably your configs.
460+ Check that your config (like ones with ` ignoreScript ` ) are actually applied,
461+ as they use on demand execution and may target wrong plugin or extension and never be executed.
462+
463+ ** Bonus** : it may not be installed, because npm install doesn't do this.
464+ See the long comment in [ npm.kt] ( ../gradle-conventions/src/main/kotlin/util/tasks/npm.kt ) .
434465
435466Something doesn't work, and you are sure it's not your fault? Report it appropriately! Don't be lazy.
436467
0 commit comments