mavenmaven-3pom.xmlmulti-modulemaven-reactor

What is the difference between using maven -pl option and running maven from module level?


Is there any difference between

C:/dev/path/to/Project> mvn package -pl MyModule -am -s settings.xml

and

C:/dev/path/to/Project/MyModule> mvn package -am -s ../settings.xml

As far as I'm concerned, the result of these two actions should be he same.

However, the behaviour seems to be different in each case: the former one seems to be more extensive; the latter ends more quickly - and I'm trying to understand why is that.


Solution

  • Let's first clarify something about multi-module (aggregator) build (that is, invoking the build from the aggregator/parent project) and building a single module.

    Let's use the following example:

    -+ modules-project
     |- module-a
     |- module-b (depends on module-a)
    

    Hence modules-project will have as part of its pom the following:

    <modules>
        <module>module-a</module>
        <module>module-b</module>
    </modules>
    

    When building from the module-project folder:

    module-project> mvn clean install
    

    The Maven Reactor will create the dependency graph of the declared modules and build them accordingly, hence module-a will be built before module-b because module-b depends on module-a

    module-b> mvn clean install
    

    Would work correctly, only building module-b, resolving module-a as a dependency (which we installed previously) and using it as part of the build classpath where required.

    If instead of invoking a clean install on modules-project we would have invoked a clean package, Maven would not have installed anything in our local Maven cache, hence the dependency to module-a in the module-b project could not be resolved. To clarify:

    module-project> mvn clean package
    

    Will still build the whole project (with all of its submodules) and create the packages (that is, the jar files).

    module-b> mvn clean package
    

    Would now fail, because the dependency to module-a is not present in the local Maven cache nor in any Maven repository, that is, it doesn't exist as a dependency and Maven doesn't know anything about other modules, it is building a simple project (a module) without any knowledge about other modules (as provided by modules-project). When building modules-project instead, Maven is building each module with much more information, knowing that a module has a dependency to another module it will not look on the local cache or on any Maven repository for inter-modules dependencies. Again, it's a reactor build.

    That's why you can build a sub-module as a separate build only if you already built the whole multi-module project and installed its artifacts at least in the local Maven cache. And that's why the best practice is always to work from the multi-module project, so that Maven has all the required information and you could:

    Let's clarify now the last point, which will also answer your question.

    modules-project> mvn clean package -pl module-a
    

    Would run fine, building only module-a as part of the reactor build. However

    modules-project> mvn clean package -pl module-b
    

    Would fail, because Maven will try as requested to build module-b, but, again, would look for module-a as a dependency and not a module, hence in the local Maven cache or in the configured Maven repository, not finding it.

    modules-project> mvn clean package -pl module-b -am
    

    Would eventually work fine, because now Maven is also building the dependent modules (thanks to -am) and knows exactly where to find them (as part of the multi-module information, that is, the modules section).

    Let's look at a last case:

    module-b> mvn clean package -am
    

    Would fail if we never installed the whole multi-module project (i.e. we always run clean package), the -am option would be ignored if not part of a reactor build (because it is an option of the reactor, not of the normal build) and Maven would still try to find module-a in local cache or in repositories.

    That's why you should always build a sub-module from its aggregator/parent and via the -pl and -am options, to make sure that:

    That's also why your observation is right, the first invocation you mentioned (building a submodule from the aggregator project) takes slightly longer because it is not simply the build of a submodule but something more (because there are more information to process and it is a different type of build, a reactor one, potentially building dependent modules also), while building directly a submodule (from its directory) is a simpler Maven build and as such also quicker (but more error prone because of the lack of some information).

    More information on these options for a reactor build could be found at: