Skip to content

Activate Maven Profile by Operating System

Published on
  • Maven
  • Java

Agent Smith from The Matrix

In rare cases, project build may require different configuration depending on operating system that runs the build.

In Maven, it can be done with Maven Profiles.


Configure Profiles

You can define profile for each supported operating system and provide different configuration, which includes dependencies, build plugins or just setting different OS specific property value.

xml
<profiles>
    <profile>
        <id>windows</id>
        <properties>
            <my.property>running.on.windows</my.property>
        </properties>
    </profile>
    <profile>
        <id>mac</id>
        <properties>
			<my.property>running.on.mac</my.property>
        </properties>
    </profile>
    <profile>
        <id>unix</id>
        <properties>
			<my.property>running.on.linux</my.property>
        </properties>
    </profile>
</profiles>

Profiles can be activated manually by setting -P flag to Maven command:

bash
$ mvn package -Pwindows

Likely, you would like to avoid the need for user to set this profile. Maven can figure it out by checking the operating system the build is running on and activating a profile for this OS:

xml
<profile>
    <id>windows</id>
	<activation>
		<os>
			<family>windows</family>
		</os>
	</activation>
    <properties>
        <my.property>running.on.windows</my.property>
    </properties>
</profile>

Activation can be narrowed to specific operating system name, architecture or even exact version. To not end up with dozens of profiles, assuming we are running builds only on x86 64bit architectures we can use family to let Maven activate the profile.

Family may have one of the following values:

  • dos
  • mac
  • netware
  • os/2
  • tandem
  • unix
  • windows
  • win9x
  • z/os
  • os/400
  • openvms

If you look closely, you may have noticed that there is no family for Linux. There is one for unix, but Mac is unix too.

Activate profile on Linux but not on Mac

When we use following profiles' config:

xml
<profiles>
    <profile>
        <id>windows</id>
        <activation>
            <os>
                <family>windows</family>
            </os>
        </activation>
        <properties>
			<my.property>running.on.windows</my.property>
        </properties>
    </profile>
    <profile>
        <id>mac</id>
        <activation>
            <os>
                <family>mac</family>
            </os>
        </activation>
        <properties>
			<my.property>running.on.mac</my.property>
        </properties>
    </profile>
    <profile>
        <id>linux</id>
        <activation>
            <os>
                <family>unix</family>
            </os>
        </activation>
        <properties>
			<my.property>running.on.linux</my.property>
        </properties>
    </profile>
</profiles>

Build will run as expected on Windows and Linux, but on Mac both mac and unix profile will be active.

To properly narrow it down to activate linux profile only when running on Linux, and mac profile only when running on Mac, the Linux profile must be activated by operating system name:

xml
<profiles>
    <profile>
        <id>windows</id>
        <activation>
            <os>
                <family>windows</family>
            </os>
        </activation>
        <properties>
			<my.property>running.on.windows</my.property>
        </properties>
    </profile>
    <profile>
        <id>mac</id>
        <activation>
            <os>
                <family>mac</family>
            </os>
        </activation>
        <properties>
			<my.property>running.on.mac</my.property>
        </properties>
    </profile>
    <profile>
        <id>linux</id>
        <activation>
            <os>
                <name>Linux</name>
            </os>
        </activation>
        <properties>
			<my.property>running.on.linux</my.property>
        </properties>
    </profile>
</profiles>

How to prevent from running on different OS or on unsupported architecture?

With such configuration, when build runs on the OS that does not match any of the activations, simply no profile will be active and likely build fails in unexpected way due to a missing whatever-you-defined-in-profile-configuration.

To avoid it, you can use maven-enforcer-plugin to ensure that one of the profiles is active:

xml
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>3.1.0</version>
            <executions>
                <execution>
                    <id>enforce-os-profile</id>
                    <goals>
                        <goal>enforce</goal>
                    </goals>
                    <configuration>
                        <rules>
                            <requireActiveProfile>
                                <profiles>windows,mac,linux</profiles>
                                <all>false</all>
                            </requireActiveProfile>
                        </rules>
                        <fail>true</fail>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Run build on different operating systems with GitHub action

If your build depends on the operating system, it is worth to run it on the CI server against each of the supported OS.

GitHub Actions supports running jobs on Ubuntu, Windows and Mac OS. A sample action that runs Maven build on each of these is:

yml
name: Build
on: [push]
jobs:
  build:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-java@v3
        with:
          distribution: 'temurin'
          java-version: '17'
          cache: maven
      - run: ./mvnw package

Unfortunately at this stage there is no out-of-the-box support for running jobs on runners with ARM processors, such as Apple M1. If that's what you need, you must use a self hosted runner on GitHub and one of the providers that offer M1 - but it is not free.

Let's stay in touch and follow me on Twitter: @maciejwalkowiak

Subscribe to RSS feed