问题
I've spent years trying to deploy libraries that use native code to Maven Central. I've run into the following problems:
- There weren't any good plugins for building native code using Maven. native-maven-plugin was a very rigid build system that, among other things, made it difficult to debug the resulting binaries. You'd have to manually synchronize the native-maven-plugin build system with the native IDE you use for debugging.
- Maven did not replace variables in deployed pom.xml files: MNG-2971, MNG-4223. This meant that libraries had to declare platform-specific dependencies once per Maven profile (as opposed to declaring the dependency once and setting a different classifier per profile); otherwise, anyone who depended on your library had to re-define those same properties in their project file in order to resolve transitive dependencies. See Maven: Using inherited property in dependency classifier causes build failure.
- Jenkins had abysmal support for running similar logic across different platforms (e.g. "shell" vs "batch" tasks, and coordinating a build across multiple machines)
- Running Windows, Linux and Mac in virtual machines was way too slow and fragile. Even if you got it working, attempting to configure the VMs as Jenkins slaves was a lesson in frustration (you'd get frequent intermittent build errors).
- Maven Central requires a main jar for artifacts that are platform-specific: OSSRH-975
- Sonatype OSS Repository Hosting and maven-release-plugin assumed that it would be possible to release a project in an atomic manner from a single machine but I need to build the OS-specific bits on separate machines.
I'm going to use this Stackoverflow question to document how I've managed to overcome these limitations.
回答1:
Here is how I overcame the aforementioned problems:
- I used CMake for building native code. The beauty of this system is that it generates project files for your favorite (native) IDE. You use the same project files to compile and debug the code. You no longer need to synchronize the two systems manually.
- Maven didn't support CMake, so I built my own plugin: https://github.com/cmake-maven-project/cmake-maven-project
- I manually hard-coded platform-specific dependencies into each Maven profile, instead of defining the dependency once with a different classifier per profile. This was more work, but it doesn't look like they will be fixing this bug in Maven anytime soon.
- I plan to investigate http://www.mojohaus.org/flatten-maven-plugin/ and https://github.com/mjiderhamn/promote-maven-plugin as alternatives in the near future.
- Jenkins pipeline does a good job of orchestrating a build across multiple machines.
- Running Jenkins slaves on virtual machines is still very error-prone but I've managed to workaround most of the problems. I've uploaded my VMWare configuration steps and Jenkins job configuration to help others get started.
- I now create an empty JAR file for platform-specific artifacts in order to suppress the Sonatype error. This was actually recommended by Sonatype's support staff.
- It turns out that maven-release-plugin delegates to other plugins under the hood. Instead of invoking it, I do the following:
- Use
mvn versions:set
to change the version number from SNAPSHOT to a release and back. - Tag and commit the release myself.
- Use
nexus-staging:rc-open
,nexus-staging:deploy -DstagingProfileId=${stagingProfileId} -DstagingRepositoryId=${stagingRepositoryId}
, andnexus-staging:rc-close
to upload artifacts from different platforms into the same repository. This is called aStaging Workflow
(referenced below). - Upon review, release the repository to Maven Central.
- Important: do not enable
<autoReleaseAfterClose>
in thenexus-staging
plugin because it closes the staging repository after each deploy instead of waiting for all deploys to complete. - Per https://issues.sonatype.org/browse/NEXUS-18753 it isn't possible to release SNAPSHOT artifacts atomically (there is no workaround). When releasing SNAPSHOTs, you need to skip
rc-open
,rc-close
and invokenexus-staging:deploy
without-DstagingProfileId=${stagingProfileId} -DstagingRepositoryId=${stagingRepositoryId}
. Each artifact will be uploaded into a separate repository.
- Use
See my Requirements API for a real-life example that works.
Other quirks to watch out for:
skipNexusStagingDeployMojo
must be false in last reactor module (otherwise no artifacts will be deployed): https://issues.sonatype.org/browse/NEXUS-12365. The best workaround is to use Maven profiles to omit whatever modules you want when deploying (don't useskipNexusStagingDeployMojo
at all)skipLocalStaging
prevents deploying multiple artifacts into the same repository: https://issues.sonatype.org/browse/NEXUS-12351
来源:https://stackoverflow.com/questions/40853862/building-and-deploying-native-code-using-maven