Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the generated BuildConfig recognizable by the IDE #36

Closed
mr3y-the-programmer opened this issue Mar 18, 2023 · 16 comments
Closed

Make the generated BuildConfig recognizable by the IDE #36

mr3y-the-programmer opened this issue Mar 18, 2023 · 16 comments

Comments

@mr3y-the-programmer
Copy link

mr3y-the-programmer commented Mar 18, 2023

Currently, when trying to use the plugin in a project, the generated BuildConfig object is inaccessible in code leading to IDE errors (e.g Unresolved reference) because the IDE isn't aware of its existence.

BuildConfig.Foo // Unresolved reference

To make the IDE recognizes it, we need to treat the generated source dir the same as the project's main source directories.
it would be helpful to update the README to include this code snippet to avoid this annoying issue.

kotlin.sourceSets {
    main {
        kotlin.srcDirs(
            file("$buildDir/generated/source/buildConfig/main"),
        )
    }
}

PR #37 fixes this, and also add the equivalent code snippet for groovy build.gradle files.

@rocketraman
Copy link

In my Kotlin multi-platform project, I had to specify $buildDir/generated/source/buildConfig/main as the source dir.

@mr3y-the-programmer
Copy link
Author

this also works for non multi-platform projects, I'll update the code snippet.

@jasonsparc
Copy link

I believe that a more correct solution is to hook into prepareKotlinIdeaImport task. See, https://twitter.com/Sellmair/status/1619308362881187840

@mr3y-the-programmer
Copy link
Author

@jasonsparc I know about that tip, but I think you misunderstood the issue's main point here, that task would make generateBuildConfig run automatically on every gradle sync without having to do that manually yourself, but you still need a way to make the IDE aware of what you've just generated, and this is what the issue is addressing

@natros
Copy link

natros commented Apr 23, 2023

I'm not sure I understand the problem, but in all my projects the generated class is always visible and accessible to the IDE.

Am I missing something?

@jasonsparc
Copy link

jasonsparc commented Apr 24, 2023

@natros That's also what I thought.

The only time the generated classes won't be recognized by the IDE is when the various generate*BuildConfig tasks haven't run yet (that is, if they've never run yet). Also, as far as I know (or at least, last time I checked the plugin's source code), the generated directories are already included in kotlin.srcDirs, since otherwise, the build won't recognize the newly generated source files. However, I could be wrong this time, or this issue might be for a different problem that I'm not getting.

If that's the case, the proper fix should go in the plugin's code, and not in the README (as in the pull request).

@mr3y-the-programmer
Copy link
Author

@natros @jasonsparc This wasn't the case for me, If I didn't add the code above to my build script, The IDE wouldn't suggest/auto-complete the generated BuildConfig, and even if I did complete it manually & add the necessary import, The IDE complains about it saying Unresolved reference thus failing the build. This is why I opened the issue to fix that problem for me & for anyone who might experience that as well (as I thought that many people had experienced that too) but, Apparently, this is not the case for everyone 🤷‍♂️.

@jasonsparc
Copy link

Hmm... I think I have an idea about what problem you're actually facing.

Are you using it for kotlin multiplatform? If yes, then I believe that the problem lies in not calling the appropriate generate*BuildConfig task for the particular target platform.

Say for example, you're expecting the generated source code to be used for a JS target named Foo, but then, you ran generateBuildConfig task. That's a mistake! Because that's actually not the correct task to run (and I believe that should be clarified in the README).

What you should instead run is a task named generateFooMainBuildConfig to generate the expected build configs. Why? Because generateBuildConfig task doesn't automatically run that custom named task, thus it won't generate the expected build configs. If instead you ran the generateFooMainBuildConfig task, it'll generate it under $buildDir/generated/source/buildConfig/fooMain (notice fooMain, not main), the one that our JS target expects, which is visible to our JS target (and not $buildDir/generated/source/buildConfig/main).

If your JS target is unnamed, I believe the name will instead be just js. The same goes for JVM targets, and for android. When using it on multiplatform, you must call the appropriate task with the corresponding name, i.e., generate<Name>MainBuildConfig, and for tests, generate<Name>TestBuildConfig, or for android unit tests, generate<Name>UnitTestBuildConfig.

Probably the assumption here is that generateBuildConfig runs all of the custom named tasks. Sadly, it does not! At least, at the moment. Thus the fix should be either, clarifying that gotcha in the README, or making sure that generateBuildConfig depends on all of those custom named tasks, so that they run automatically.

@rocketraman Please take a look at this too, as you've said you're using it for kotlin multiplatform.

@mr3y-the-programmer If the problem persists despite my clarifications, perhaps provide a small demo project to reproduce the issue in a simple and contained way. That way, we could pinpoint the actual issue, determine the root cause, and fix it from the root.

@rocketraman
Copy link

rocketraman commented Apr 24, 2023

@jasonsparc Things don't appear to be that simple.

  1. BuildConfig (generally, unless user does some weird config) generates pure Kotlin code with no platform deps. Therefore, there is no need on a multi-platform project to generate one version for JS and another version for JVM, etc. A single source file generated in the commonMain source set is sufficent for use on all platforms.

  2. It doesn't appear to work the way you say. My project has "frontend" and "backend" named targets, js and jvm respectively. However, when I call generateFrontendMainBuildConfig and generateBackendMainBuildConfig, no BuildConfig.kt is generated at all. However, when I call generateBuildConfig, the following file is generated:

shared/build/generated/source/buildConfig/main/main/my/package/BuildConfig.kt

IMO, this is actually doing the right thing for a MPP project as per point 1, as I don't want a separate backend and frontend config -- I want one shared one.

@jasonsparc
Copy link

jasonsparc commented Apr 24, 2023

@rocketraman I didn't say that generateFooMainBuildConfig would generate the commonMain code. It would simply generate what you set via buildConfig.sourceSets.named("fooMain"). If you want common code, you'll have to run generateBuildConfig for that, and you'll have to set it up via buildConfig.

What's not clear to me is that, how come it won't be recognized by the IDE after such tasks have run? Now, set aside the IDE, does it not work with just building it with the gradle build tool? If it works, then there might be something wrong with the IDE. If it doesn't, then there might be something wrong with the plugin.

I'm currently using a multiplatform project, and I can confirm that doing a gradlew clean followed by a gradlew run (for the JVM), works as expected, without needing to manually hook $buildDir/generated/source/buildConfig/main into kotlin.srcDirs. As for the plugin's version, I'm currently using 3.1.0. My task tree for gradlew run looks something like as follows:

11:21:04 PM: Executing 'taskTree run --no-configuration-cache'...

...

------------------------------------------------------------
Project ':kokoro.app.desktop'
------------------------------------------------------------

:kokoro.app.desktop:run
+--- :kokoro.app:desktopJar
|    +--- :kokoro.app:compileKotlinDesktop
|    |    +--- :kokoro.app:generateAppMainBuildConfig
|    |    +--- :kokoro.app:generateBuildConfig
|    |    +--- :kokoro.app:generateDesktopMainBuildConfig
|    |    +--- :kokoro.app:generateJvmishMainBuildConfig
|    |    \--- :kokoro.lib.internal:desktopJar
|    |         +--- :kokoro.lib.internal:compileKotlinDesktop
|    |         |    +--- :kokoro.lib.internal:generateAppMainBuildConfig
|    |         |    +--- :kokoro.lib.internal:generateBuildConfig
|    |         |    +--- :kokoro.lib.internal:generateDesktopMainBuildConfig
|    |         |    \--- :kokoro.lib.internal:generateJvmishMainBuildConfig
|    |         +--- :kokoro.lib.internal:desktopMainClasses
|    |         |    +--- :kokoro.lib.internal:compileKotlinDesktop *
|    |         |    \--- :kokoro.lib.internal:desktopProcessResources
|    |         \--- :kokoro.lib.internal:desktopProcessResources *
|    +--- :kokoro.app:desktopMainClasses
|    |    +--- :kokoro.app:compileKotlinDesktop *
|    |    \--- :kokoro.app:desktopProcessResources
|    \--- :kokoro.app:desktopProcessResources *
+--- :kokoro.app.desktop:classes
|    +--- :kokoro.app.desktop:compileJava
|    |    +--- :kokoro.app:desktopJar *
|    |    \--- :kokoro.app.desktop:compileKotlin
|    |         \--- :kokoro.app:desktopJar *
|    \--- :kokoro.app.desktop:processResources
+--- :kokoro.app.desktop:compileKotlin *
\--- :kokoro.lib.internal:desktopJar *

(*) - subtree omitted (printed previously)
Add --repeat to allow printing a subtree of the same task more than once.

I can confirm that after running gradlew clean, all the generated build configs are errors (red) in my IDE (Android Studio Flamingo 2022.2.1). But after gradlew run, everything works fine: the errors disappear too. That is, I didn't even need to set up kotlin.srcDirs manually.

@jasonsparc
Copy link

jasonsparc commented Apr 24, 2023

Also, for further context. The hierarchy for my multiplatform sources is something like:

common
  app
    jvmish
      android
      desktop
    native
      ...

May I kindly ask for you guys to do the same?

I find the issue really weird. But I really don't want to dismiss it as it could be a valid issue. Perhaps some kind of incompatible interactions with your plugins? As I said before, a minimal reproduceable demo project would really help, instead of simply proposing a weird hack in the README.

@rocketraman
Copy link

@jasonsparc Thanks for the clarification. Digging a bit deeper, a plain vanilla gradle build works fine for me without the extra srcDirs declaration. And funnily enough, now so does the IDE, with no other changes or explicit source set declarations in my Gradle buildConfig configuration! So TBH, I have no idea why this didn't work for me before without that extra srcDirs declaration.

@mr3y-the-programmer
Copy link
Author

@jasonsparc No, I'm not using the plugin in a multiplatform project, it is a relatively small android app with all the code in a single module app.

I'll create a minimal reproducible project, and I'll inform you

@mr3y-the-programmer
Copy link
Author

@jasonsparc Here's a sample project: https://github.com/mr3y-the-programmer/build-config-bug.
it is a skeleton android app that has no plugins applied in the build script other than build config plugin alongside com.android.application & org.jetbrains.kotlin.android that applied to every android project.

Steps to reproduce the issue:

  1. clone the project locally git clone https://github.com/mr3y-the-programmer/build-config-bug.git
  2. Build the project using IDE or from the command line directly with ./gradlew build

Expected result:
The build should fail from both IDE and the command line with the message Unresolved reference: BuildConfig due to calling BuildConfig in this line MainActivity.kt#L29

Now, Uncomment the workaround here at build.gradle#L51, sync the project, and finally rerun build again from the IDE or from the command line, the build should complete successfully from both without any issues.

Additional Context:
Gradle version: 8.1.1
build config plugin version: 3.1.0 (latest version)
IDE: Android studio Flamingo that is based on Intellij IDEA 2022.2

@gmazzo
Copy link
Owner

gmazzo commented Apr 25, 2023

Ok after reviewing this, I think the upcoming major release will also fix this. Basically, Android was never supported, because it has its own BuildConfig feature.

The plugin was "working" in a detached way (no linked to any source set) because kotlin-android was not a recognized plugin. That's why you needed the extra .srcDir.

I'm introducing support in the upcoming major release.

@gmazzo
Copy link
Owner

gmazzo commented Apr 25, 2023

This will be fix on 4.0.1 version

@gmazzo gmazzo closed this as completed Apr 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
5 participants