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

Exclude dependencies from native-image #612

Open
snicoll opened this issue Jul 29, 2024 · 9 comments
Open

Exclude dependencies from native-image #612

snicoll opened this issue Jul 29, 2024 · 9 comments
Labels
enhancement New feature or request maven-plugin Related to Maven plugin

Comments

@snicoll
Copy link
Collaborator

snicoll commented Jul 29, 2024

Is your feature request related to a problem? Please describe.
Maven has a limited list of dependency scopes and it's not possible to create custom ones. As such, dependencies that are development only can end up on the classpath. This has caused issues in the past for things that need to build an executable based on a Maven project.

Spring Boot has had several issues such as spring-projects/spring-boot#13289 and implemented several features to allow dependencies to be excluded:

The Maven plugin for native build tools urrently works in two modes: it builds the classpath itself, or it lets you define it. It would be nice if we could configure it to be able to exclude certain dependencies that shouldn't be analyzed by native-image in the first place.

Describe the solution you'd like
A way to exclude a dependency. Either by providing the GAV in the plugin configuration or via a manifest entry. The latter looks less invasive and would work out of the box.

Describe alternatives you've considered
None as building the classpath ourselves isn't really practical with Maven. The plugin is configured in our maven parent and used in a wide range of contexts.

@mhalbritter
Copy link

Our usecase, as described in spring-projects/spring-boot#32853 is that we have the devtools on the runtime classpath. Native image automatically includes the whole runtime classpath in the native image (at least what's reachable).

On Spring Boot startup, the spring.factories contained in the devtools instructs the Spring Framework to enable devtools. However, devtools in a native image don't make much sense - these tools are for development only.

We worked around that by adding an if in the devtools startup and let it disable itself if it's running in a native image - however, the code is still contained in the native image.

To fix that problem at the root, it would be nice to do something like this:

<build>
  <plugins>
    <plugin>
      <groupId>org.graalvm.buildtools</groupId>
      <artifactId>native-maven-plugin</artifactId>
      <configuration>
        <excludeDependency> <!-- Or maybe just name the tag 'exclude'? -->
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-devtools</artifactId>
        </excludeDependency>
      </configuration>
    </plugin>
  </plugins>
</build>

and the native-maven-plugin would not include any classes from that jar in the native image.

@mhalbritter
Copy link

mhalbritter commented Aug 6, 2024

Another option would be, like Stephane suggested, to add a key to the manifest (e.g. Native-Image-Exclude: true) and the native image build tools then exclude that from the classpath.

This approach would be more flexible, as this doesn't need a hard-coded list of dependencies.

@graemerocher
Copy link

We hit similar issues I believe. Just out of interest.. does using provided scope not work?

@mhalbritter
Copy link

mhalbritter commented Aug 6, 2024

The devtools should be on the classpath when developing the application on the JVM but not when building the native image. Usually, this is in the pom.xml with devtools:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <scope>runtime</scope>
      <optional>true</optional>
    </dependency>

@vjovanov vjovanov added the maven-plugin Related to Maven plugin label Sep 2, 2024
@alvarosanchez alvarosanchez removed their assignment Sep 2, 2024
@alvarosanchez
Copy link
Member

The devtools should be on the classpath when developing the application on the JVM but not when building the native image

You can achieve that with provided scope.

@mhalbritter
Copy link

It should be on the runtime classpath when developing the application (it does stuff when you run the application on the JVM, like reloading classes), but it should not be on the classpath when compiling the native image. I don't think this is possible with the provided scope?

provided: This is much like compile, but indicates you expect the JDK or a container to provide the dependency at runtime.

Who would provide this dependency?

@alvarosanchez
Copy link
Member

So provided is close to compileOnly in Gradle. Those dependencies are in the compilation classpath, but certainly not at runtime.

That said, if you have control over the classpath of the app running in dev mode, you could choose to include dependencies in provided scope. This is what we do in the Micronaut Maven Plugin, so effectively, provided becomes a sort of "development only" scope.

And this will also have the desired effect of not including such dependencies in the native image.

@mhalbritter
Copy link

mhalbritter commented Sep 3, 2024

if you have control over the classpath of the app running in dev mode

While this could be made to work with mvn spring-boot:run, I don't think this will be possible when running the application from the IDE, which a lot of users do. Or did you get this working in Micronaut?

@alvarosanchez
Copy link
Member

Yes, in Intellij IDEA at least, provided dependencies are included in the runtime classpath.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request maven-plugin Related to Maven plugin
Projects
None yet
Development

No branches or pull requests

5 participants