CINXE.COM
Java Packaging HOWTO :: Fedora Docs
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Java Packaging HOWTO :: Fedora Docs</title> <link rel="canonical" href="https://docs.fedoraproject.org/en-US/java-packaging-howto/"> <meta name="generator" content="Antora 3.1.4"> <link rel="stylesheet" href="../_/css/site.css"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous"> <link rel="stylesheet" href="../_/css/vendor/tabs.css"> <meta property="og:type" content="website"> <meta property="og:site_name" content="Fedora Docs"> <meta property="og:title" content="Java Packaging HOWTO"> <meta property="og:description" content="Learn more about Fedora Linux, the Fedora Project & the Fedora Community."> <meta property="og:image" content="https://docs.fedoraproject.org/en-US/_/img/docs_logo.png"> <script>if (localStorage.darkmode === 'true' || (!('darkmode' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { document.documentElement.classList.add('dark');} else {document.documentElement.classList.remove('dark');}</script> </head> <body class="article dark:bg-fp-blue-darkest text-black dark:text-white"> <!-- Add any HTML code to show at the top of each page — like a banner to a survey, some announcement, etc. Leave this file empty to not show anything--> <header class="header" role="banner"> <nav class="fixed z-50 top-0 w-full bg-gradient-to-l from-fp-blue to-fp-blue-light dark:bg-none dark:bg-fp-blue-dark" style=""> <div class="mx-auto px-2 sm:px-6 lg:px-8"> <div class="relative flex h-14 items-center justify-between"> <div class="flex flex-1 items-center justify-center sm:items-stretch sm:justify-start" > <div class="flex flex-shrink-0 items-center"> <a href="https://docs.fedoraproject.org/en-US"> <img class="h-6 z-10 w-auto" src="../_/img/docs_logo_white.png"> </a> </div> <div class="hidden sm:ml-auto sm:block"> <div class="flex space-x-4"> <div id="search-field" class="relative inline-flex cursor-pointer items-center rounded px-4 text-xs text-gray-500 dark:text-gray-200"> <svg class="absolute left-6 fill-gray-400 dark:fill-gray-400 h-3" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z"/></svg> <input id="search-input" class="pl-6 pr-28 h-8 w-64 rounded-xl dark:bg-black" type="text" placeholder="Search Docs"> <label class="ml-2 absolute right-6 filter checkbox border-l border-gray-500 pl-2"> <input type="checkbox" class="appearance-none h-3 w-3 border border-gray-500 rounded bg-white dark:bg-black checked:bg-fp-blue-light checked:border-fp-blue-light dark:checked:bg-fp-blue dark:checked:border-fp-blue focus:outline-none transition duration-200 cursor-pointer my-0.5 mr-1 float-left" data-facet-filter="component:java-packaging-howto"> In this section </label> </div> </div> </div> <button type="button" id="themeSwitch" class="hidden sm:block stroke-white fill-white "> <span class="dark:hidden"> <svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-6 h-6"> <path d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"></path> <path d="M12 4v1M17.66 6.344l-.828.828M20.005 12.004h-1M17.66 17.664l-.828-.828M12 20.01V19M6.34 17.664l.835-.836M3.995 12.004h1.01M6 6l.835.836"></path> </svg> </span> <span class="hidden dark:inline"> <svg viewBox="0 0 512 512" class="w-4 h-4"> <path d="M421.6 379.9c-.6641 0-1.35 .0625-2.049 .1953c-11.24 2.143-22.37 3.17-33.32 3.17c-94.81 0-174.1-77.14-174.1-175.5c0-63.19 33.79-121.3 88.73-152.6c8.467-4.812 6.339-17.66-3.279-19.44c-11.2-2.078-29.53-3.746-40.9-3.746C132.3 31.1 32 132.2 32 256c0 123.6 100.1 224 223.8 224c69.04 0 132.1-31.45 173.8-82.93C435.3 389.1 429.1 379.9 421.6 379.9zM255.8 432C158.9 432 80 353 80 256c0-76.32 48.77-141.4 116.7-165.8C175.2 125 163.2 165.6 163.2 207.8c0 99.44 65.13 183.9 154.9 212.8C298.5 428.1 277.4 432 255.8 432z"/> </svg> </span> </button> </div> </div> </div> </nav> </header> <div class="body"> <div class="nav-container dark:text-gray-300 bg-fp-gray-lightest dark:bg-fp-blue-darker dark:border-r dark:border-gray-800" data-component="java-packaging-howto" data-version="master"> <aside class="nav"> <div class="panels"> <div class="nav-panel-explore bg-gray-50 dark:bg-fp-blue-darkest is-active" data-panel="explore"> <div class="context dark:border-t dark:border-gray-800"> <span class="title">Java Packaging HOWTO</span> <span class="version"></span> </div> <ul class="components bg-gray-100 dark:bg-fp-blue-darkest"> <li class="component"> <a class="title" href="../arm-sbc/">ARM Single Board Computers</a> </li> <li class="component"> <a class="title" href="../ask-fedora-sops/">Ask Fedora SOPs</a> </li> <li class="component"> <a class="title" href="../community/">Community Architecture (CommArch)</a> </li> <li class="component"> <a class="title" href="../cle/">Community Linux Engineering</a> </li> <li class="component"> <a class="title" href="../defensive-coding/">Defensive Coding Guide</a> </li> <li class="component"> <a class="title" href="../emerging/">Emerging Fedora Desktops</a> </li> <li class="component"> <a class="title" href="../engineering/">Engineering Teams</a> </li> <li class="component"> <a class="title" href="../epel/">EPEL</a> </li> <li class="component"> <a class="title" href="../a11y/">Fedora Accessibility (a11y) WG</a> </li> <li class="component"> <a class="title" href="../fedora-accounts/">Fedora Accounts</a> </li> <li class="component"> <a class="title" href="../fedora-asahi-remix/">Fedora Asahi Remix</a> </li> <li class="component"> <a class="title" href="../badges/">Fedora Badges</a> </li> <li class="component"> <a class="title" href="../ci/">Fedora CI</a> </li> <li class="component"> <a class="title" href="../commops/">Fedora Community Ops</a> </li> <li class="component"> <a class="title" href="../containers/">Fedora Container Docs</a> </li> <li class="component"> <a class="title" href="../fedora-coreos/">Fedora CoreOS</a> </li> <li class="component"> <a class="title" href="../council/">Fedora Council</a> </li> <li class="component"> <a class="title" href="../design/">Fedora Design Team</a> </li> <li class="component"> <a class="title" href="../dei/">Fedora Diversity, Equity, and Inclusion (DEI)</a> </li> <li class="component"> <a class="title" href="../fedora-docs/">Fedora Docs Team</a> </li> <li class="component"> <a class="title" href="../docs/">Fedora Documentation</a> </li> <li class="component"> <a class="title" href="../eln/">Fedora ELN</a> </li> <li class="component"> <a class="title" href="../gaming/">Fedora Gaming</a> </li> <li class="component"> <a class="title" href="../i3/">Fedora i3 S.I.G.</a> </li> <li class="component"> <a class="title" href="../infra/">Fedora Infrastructure & Release Engineering</a> </li> <li class="component"> <a class="title" href="../iot/">Fedora Internet Of Things</a> </li> <li class="component"> <a class="title" href="../iot-wg/">Fedora IoT Working Group</a> </li> <li class="component"> <a class="title" href="../fedora-join/">Fedora Join SIG</a> </li> <li class="component"> <a class="title" href="../fedora-kinoite/">Fedora Kinoite</a> </li> <li class="component"> <a class="title" href="../legal/">Fedora Legal</a> </li> <li class="component"> <a class="title" href="../releases/">Fedora Linux Releases</a> </li> <li class="component"> <a class="title" href="../localization/">Fedora Localization Team</a> </li> <li class="component"> <a class="title" href="../fedora-magazine/">Fedora Magazine</a> </li> <li class="component"> <a class="title" href="../marketing/">Fedora Marketing Team</a> </li> <li class="component"> <a class="title" href="../mentored-projects/">Fedora Mentored Projects</a> </li> <li class="component"> <a class="title" href="../mindshare-committee/">Fedora Mindshare Committee</a> </li> <li class="component"> <a class="title" href="../program_management/">Fedora Program Management</a> </li> <li class="component"> <a class="title" href="../project/">Fedora Project</a> </li> <li class="component"> <a class="title" href="../qa-docs/">Fedora Quality Docs</a> </li> <li class="component"> <a class="title" href="../rawhide-gating/">Fedora Rawhide Gating</a> </li> <li class="component"> <a class="title" href="../robotics-sig/">Fedora Robotics SIG</a> </li> <li class="component"> <a class="title" href="../fedora-server/">Fedora Server Documentation</a> </li> <li class="component"> <a class="title" href="../server-working-group/">Fedora Server Working Group</a> </li> <li class="component"> <a class="title" href="../fedora-silverblue/">Fedora Silverblue</a> </li> <li class="component"> <a class="title" href="../spins-labs/">Fedora Spins & Labs</a> </li> <li class="component"> <a class="title" href="../fedora-sericea/">Fedora Sway Atomic</a> </li> <li class="component"> <a class="title" href="../teleirc-sig/">Fedora TeleIRC SIG</a> </li> <li class="component"> <a class="title" href="../tools/">Fedora Tools</a> </li> <li class="component"> <a class="title" href="../fedora/latest/">Fedora User Docs</a> <ul class="versions"> <li class="version"> <a href="../fedora/rawhide/">rawhide</a> </li> <li class="version is-latest"> <a href="../fedora/latest/">f41</a> </li> <li class="version"> <a href="../fedora/f40/">f40</a> </li> <li class="version"> <a href="../fedora/f39/">f39</a> </li> <li class="version"> <a href="../fedora/f38/">f38</a> </li> <li class="version"> <a href="../fedora/f37/">f37</a> </li> <li class="version"> <a href="../fedora/f36/">f36</a> </li> <li class="version"> <a href="../fedora/f35/">f35</a> </li> <li class="version"> <a href="../fedora/f34/">f34</a> </li> <li class="version"> <a href="../fedora/f33/">f33</a> </li> <li class="version"> <a href="../fedora/f32/">f32</a> </li> <li class="version"> <a href="../fedora/f31/">f31</a> </li> <li class="version"> <a href="../fedora/f30/">f30</a> </li> <li class="version"> <a href="../fedora/f29/">f29</a> </li> <li class="version"> <a href="../fedora/f28/">f28</a> </li> <li class="version"> <a href="../fedora/f27/">f27</a> </li> <li class="version"> <a href="../fedora/f26/">f26</a> </li> </ul> </li> <li class="component"> <a class="title" href="../websites/">Fedora Websites & Apps</a> </li> <li class="component"> <a class="title" href="../workstation-docs/">Fedora Workstation Documentation</a> </li> <li class="component"> <a class="title" href="../workstation-working-group/">Fedora Workstation Working Group</a> </li> <li class="component"> <a class="title" href="../bootc/">Fedora/CentOS bootc</a> </li> <li class="component"> <a class="title" href="../fesco/">FESCo</a> </li> <li class="component"> <a class="title" href="../flatpak/">Flatpak</a> </li> <li class="component is-current"> <a class="title" href="./">Java Packaging HOWTO</a> </li> <li class="component"> <a class="title" href="../docs-l10n/">Localization help and stats</a> </li> <li class="component"> <a class="title" href="../mindshare/">Mindshare Teams</a> </li> <li class="component"> <a class="title" href="../minimization/">Minimization</a> </li> <li class="component"> <a class="title" href="../modularity/">Modularity</a> </li> <li class="component"> <a class="title" href="../neurofedora/overview/">NeuroFedora User Documentation</a> </li> <li class="component"> <a class="title" href="../package-maintainers/">Package Maintainers</a> </li> <li class="component"> <a class="title" href="../packaging-guidelines/">Packaging Guidelines</a> </li> <li class="component"> <a class="title" href="../quick-docs/">Quick Docs</a> </li> <li class="component"> <a class="title" href="../remix-building/remix-ci/">Remix Docs</a> </li> <li class="component"> <a class="title" href="../reproducible-builds/">Reproducible Builds</a> </li> </ul> </div> </div> </aside> </div> <main class="article"> <div class="toolbar bg-fp-gray-lightest dark:bg-fp-blue-darkest dark:text-gray-300 dark:border-b dark:border-gray-800" role="navigation"> <button class="toolbar-icon nav-toggle"></button> <a href="../docs/" class="toolbar-icon home-link"></a> <nav class="crumbs" role="navigation" aria-label="breadcrumbs"> </nav> <div class="page-languages"> <button class="languages-menu-toggle" title="Show other languages of the site"> en-US </button> <div class="languages-menu"> <a class="language" href="../../en-US/java-packaging-howto/">en-US</a> <a class="language" href="../../ar/java-packaging-howto/">ar</a> <a class="language" href="../../ast/java-packaging-howto/">ast</a> <a class="language" href="../../az/java-packaging-howto/">az</a> <a class="language" href="../../be/java-packaging-howto/">be</a> <a class="language" href="../../bg/java-packaging-howto/">bg</a> <a class="language" href="../../bn/java-packaging-howto/">bn</a> <a class="language" href="../../ca/java-packaging-howto/">ca</a> <a class="language" href="../../cs/java-packaging-howto/">cs</a> <a class="language" href="../../de/java-packaging-howto/">de</a> <a class="language" href="../../el/java-packaging-howto/">el</a> <a class="language" href="../../es/java-packaging-howto/">es</a> <a class="language" href="../../es_419/java-packaging-howto/">es_419</a> <a class="language" href="../../fa/java-packaging-howto/">fa</a> <a class="language" href="../../fi/java-packaging-howto/">fi</a> <a class="language" href="../../fil/java-packaging-howto/">fil</a> <a class="language" href="../../fr/java-packaging-howto/">fr</a> <a class="language" href="../../fur/java-packaging-howto/">fur</a> <a class="language" href="../../ga/java-packaging-howto/">ga</a> <a class="language" href="../../he/java-packaging-howto/">he</a> <a class="language" href="../../hi/java-packaging-howto/">hi</a> <a class="language" href="../../hr/java-packaging-howto/">hr</a> <a class="language" href="../../hu/java-packaging-howto/">hu</a> <a class="language" href="../../id/java-packaging-howto/">id</a> <a class="language" href="../../it/java-packaging-howto/">it</a> <a class="language" href="../../ja/java-packaging-howto/">ja</a> <a class="language" href="../../jp/java-packaging-howto/">jp</a> <a class="language" href="../../ka/java-packaging-howto/">ka</a> <a class="language" href="../../kab/java-packaging-howto/">kab</a> <a class="language" href="../../ko/java-packaging-howto/">ko</a> <a class="language" href="../../mr/java-packaging-howto/">mr</a> <a class="language" href="../../ms/java-packaging-howto/">ms</a> <a class="language" href="../../my/java-packaging-howto/">my</a> <a class="language" href="../../nb_NO/java-packaging-howto/">nb_NO</a> <a class="language" href="../../ne/java-packaging-howto/">ne</a> <a class="language" href="../../nl/java-packaging-howto/">nl</a> <a class="language" href="../../nn/java-packaging-howto/">nn</a> <a class="language" href="../../or/java-packaging-howto/">or</a> <a class="language" href="../../pl/java-packaging-howto/">pl</a> <a class="language" href="../../pt/java-packaging-howto/">pt</a> <a class="language" href="../../pt_BR/java-packaging-howto/">pt_BR</a> <a class="language" href="../../pt_PT/java-packaging-howto/">pt_PT</a> <a class="language" href="../../ro/java-packaging-howto/">ro</a> <a class="language" href="../../ru/java-packaging-howto/">ru</a> <a class="language" href="../../si/java-packaging-howto/">si</a> <a class="language" href="../../sk/java-packaging-howto/">sk</a> <a class="language" href="../../sq/java-packaging-howto/">sq</a> <a class="language" href="../../sv/java-packaging-howto/">sv</a> <a class="language" href="../../sw/java-packaging-howto/">sw</a> <a class="language" href="../../te/java-packaging-howto/">te</a> <a class="language" href="../../tr/java-packaging-howto/">tr</a> <a class="language" href="../../tzm/java-packaging-howto/">tzm</a> <a class="language" href="../../uk/java-packaging-howto/">uk</a> <a class="language" href="../../ur/java-packaging-howto/">ur</a> <a class="language" href="../../ur_PK/java-packaging-howto/">ur_PK</a> <a class="language" href="../../uz/java-packaging-howto/">uz</a> <a class="language" href="../../zh_CN/java-packaging-howto/">zh_CN</a> <a class="language" href="../../zh_Hans/java-packaging-howto/">zh_Hans</a> <a class="language" href="../../zh_Hant/java-packaging-howto/">zh_Hant</a> <a class="language" href="../../zh_TW/java-packaging-howto/">zh_TW</a> </div> </div> <div class="edit-this-page"><a href="https://github.com/fedora-java/howto/commits/master/modules/ROOT/pages/index.adoc" title="Page history"><i class="fas fa-history"></i></a></div> <div class="edit-this-page"><a href="https://github.com/fedora-java/howto/edit/master/modules/ROOT/pages/index.adoc" title="Edit this Page"><i class="fas fa-edit"></i></a></div> <div class="edit-this-page"><a href="https://github.com/fedora-java/howto/issues/new?title=[master] Doc issue in file modules/ROOT/pages/index.adoc" title="Report an issue"><i class="fas fa-bug"></i></a></div> </div> <div class="content"> <aside class="toc sidebar dark:text-fp-gray-light" data-title="Contents" data-levels="2"> <div class="toc-content"> <div class="toc-menu"></div> <div class="pt-6"> </div> </div> </aside> <article class="doc dark:text-gray-100"> <h1 class="page mt-8 mb-1">Java Packaging HOWTO</h1> <div class="is-before-toc text-xs text-gray-400 border-b border-gray-300 mb-6 pb-1"> </div> <div id="toc" class="toc"> <div id="toctitle">Table of Contents</div> <ul class="sectlevel1"> <li><a href="#_authors_and_contributing">Authors and contributing</a></li> <li><a href="#_abstract">Abstract</a></li> <li><a href="#_introduction">1. Introduction</a> <ul class="sectlevel2"> <li><a href="#_basic_introduction_to_packaging_reasons_problems_rationale">1.1. Basic introduction to packaging, reasons, problems, rationale</a></li> <li><a href="#_for_packagers">1.2. For Packagers</a> <ul class="sectlevel3"> <li><a href="#_example_java_project">1.2.1. Example Java Project</a></li> <li><a href="#_build_system_identification">1.2.2. Build System Identification</a></li> <li><a href="#_quiz_for_packagers">1.2.3. Quiz for Packagers</a></li> </ul> </li> <li><a href="#_for_java_developers">1.3. For Java Developers</a> <ul class="sectlevel3"> <li><a href="#_example_rpm_project">1.3.1. Example RPM Project</a></li> <li><a href="#_querying_repositories">1.3.2. Querying repositories</a></li> <li><a href="#_quiz_for_java_developers">1.3.3. Quiz for Java Developers</a></li> </ul> </li> </ul> </li> <li><a href="#_java_specifics_in_fedora_for_users_and_developers">2. Java Specifics in Fedora for Users and Developers</a> <ul class="sectlevel2"> <li><a href="#_java_implementation_in_fedora">2.1. Java implementation in Fedora</a> <ul class="sectlevel3"> <li><a href="#_switching_between_different_java_implementations">2.1.1. Switching between different Java implementations</a></li> </ul> </li> <li><a href="#_building_classpath_with_build_classpath">2.2. Building classpath with <code>build-classpath</code></a></li> <li><a href="#_building_jar_repository_with_build_jar_repository">2.3. Building JAR repository with <code>build-jar-repository</code></a></li> </ul> </li> <li><a href="#_java_specifics_in_fedora_for_packagers">3. Java Specifics in Fedora for Packagers</a> <ul class="sectlevel2"> <li><a href="#_directory_layout">3.1. Directory Layout</a></li> <li><a href="#_jar_file_identification">3.2. JAR File Identification</a> <ul class="sectlevel3"> <li><a href="#_relative_paths">3.2.1. Relative paths</a></li> <li><a href="#_artifact_specification">3.2.2. Artifact specification</a></li> <li><a href="#_aliases">3.2.3. Aliases</a></li> <li><a href="#_compatibility_versions">3.2.4. Compatibility versions</a></li> </ul> </li> <li><a href="#_dependency_handling">3.3. Dependency Handling</a></li> <li><a href="#_javadoc_packages">3.4. Javadoc packages</a></li> <li><a href="#_core_java_packages">3.5. Core Java packages</a> <ul class="sectlevel3"> <li><a href="#_jvm">3.5.1. JVM</a></li> <li><a href="#_java_packages_tools">3.5.2. Java Packages Tools</a></li> </ul> </li> </ul> </li> <li><a href="#_packaging_best_practices">4. Packaging Best Practices</a></li> <li><a href="#_generic_java_builds">5. Generic Java Builds</a> <ul class="sectlevel2"> <li><a href="#_generating_application_shell_scripts">5.1. Generating Application Shell Scripts</a></li> <li><a href="#_replacing_jars_with_symlinks_using_xmvn_subst">5.2. Replacing JARs with symlinks using <code>xmvn-subst</code></a></li> </ul> </li> <li><a href="#_ant">6. Ant</a> <ul class="sectlevel2"> <li><a href="#_apache_ivy">6.1. Apache Ivy</a></li> </ul> </li> <li><a href="#_maven">7. Maven</a> <ul class="sectlevel2"> <li><a href="#_packaging_maven_project">7.1. Packaging Maven project</a></li> <li><a href="#_macros_for_maven_build_configuration">7.2. Macros for Maven build configuration</a> <ul class="sectlevel3"> <li><a href="#_installing_additional_artifacts">7.2.1. Installing additional artifacts</a></li> <li><a href="#_additional_mappings">7.2.2. Additional Mappings</a></li> <li><a href="#_alternative_jar_file_names">7.2.3. Alternative JAR File Names</a></li> <li><a href="#_single_artifact_per_package">7.2.4. Single Artifact Per Package</a></li> <li><a href="#_assignment_of_the_maven_artifacts_to_the_subpackages">7.2.5. Assignment of the Maven Artifacts to the Subpackages</a></li> <li><a href="#_modifying_xmvn_configuration_from_within_spec_file">7.2.6. Modifying XMvn configuration from within spec file</a></li> </ul> </li> <li><a href="#_macros_for_pom_modification">7.3. Macros for POM modification</a> <ul class="sectlevel3"> <li><a href="#_dependency_manipulation_macros">7.3.1. Dependency manipulation macros</a></li> <li><a href="#_adding_removing_plugins">7.3.2. Adding / removing plugins</a></li> <li><a href="#_disabling_unneeded_modules">7.3.3. Disabling unneeded modules</a></li> <li><a href="#_working_with_parent_pom_references">7.3.4. Working with parent POM references</a></li> <li><a href="#_macros_for_performing_generic_modifications">7.3.5. Macros for performing generic modifications</a></li> </ul> </li> </ul> </li> <li><a href="#_common_errors">8. Common Errors</a> <ul class="sectlevel2"> <li><a href="#_missing_dependency">8.1. Missing dependency</a></li> <li><a href="#_compilation_failure">8.2. Compilation failure</a></li> <li><a href="#_requires_cannot_be_generated">8.3. Requires cannot be generated</a></li> <li><a href="#_dependencies_with_scope_system">8.4. Dependencies with scope <code>system</code></a></li> </ul> </li> <li><a href="#_migration_from_older_tools">9. Migration from older tools</a> <ul class="sectlevel2"> <li><a href="#_add_maven_depmap_macro">9.1. <code>%add_maven_depmap</code> macro</a></li> </ul> </li> </ul> </div> <div class="sect1"> <h2 id="_authors_and_contributing"><a class="anchor" href="#_authors_and_contributing"></a>Authors and contributing</h2> <div class="sectionbody"> <div class="paragraph"> <p>The authors of this document are:</p> </div> <div class="ulist"> <ul> <li> <p>Mikolaj Izdebski, Red Hat</p> </li> <li> <p>Nicolas Mailhot, JPackage Project</p> </li> <li> <p>Stanislav Ochotnicky, Red Hat</p> </li> <li> <p>Ville Skyttä, JPackage Project</p> </li> <li> <p>Michal Srb, Red Hat</p> </li> <li> <p>Michael Simacek, Red Hat</p> </li> <li> <p>Marián Konček, Red Hat</p> </li> </ul> </div> <div class="paragraph"> <p>This document is free software; see the <a href="https://github.com/fedora-java/howto/blob/master/LICENSE">license</a> for terms of use, distribution and / or modification.</p> </div> <div class="paragraph"> <p>The source code for this document is available in <a href="https://github.com/fedora-java/howto">git repository</a>. Instructions for building it from sources are available in <a href="https://github.com/fedora-java/howto/blob/master/README.md">README file</a>.</p> </div> <div class="paragraph"> <p>This document is developed as part of Javapackages community project, which welcomes new contributors. Requests and comments related to this document should be <a href="https://bugzilla.redhat.com/enter_bug.cgi?product=fedora&component=java-packaging-howto">reported at Red Hat Bugzilla</a>.</p> </div> <div class="paragraph"> <p>Before contributing please read the <a href="https://github.com/fedora-java/howto/blob/master/README.md">README file</a>, which among other things includes basic rules which should be followed when working on this document. You can send patches to the <a href="https://bugzilla.redhat.com/">Red Hat Bugzilla</a>. They should be in git format and should be prepared against <code>master</code> branch in git. Alternatively you can also send pull requests at <a href="https://github.com/fedora-java/howto">Github repository</a>.</p> </div> </div> </div> <div class="sect1"> <h2 id="_abstract"><a class="anchor" href="#_abstract"></a>Abstract</h2> <div class="sectionbody"> <div class="paragraph"> <p>This document aims to help developers create and maintain Java packages in Fedora. It <strong>does not</strong> supersede or replace <a href="https://docs.fedoraproject.org/en-US/packaging-guidelines/Java/">Java Packaging Guidelines</a>, but rather aims to document tools and techniques used for packaging Java software on Fedora.</p> </div> </div> </div> <div class="sect1"> <h2 id="_introduction"><a class="anchor" href="#_introduction"></a>1. Introduction</h2> <div class="sectionbody"> <div class="paragraph"> <p>Clean Java packaging has historically been a daunting task. Lack of any standard addressing the physical location of files on the system combined with the common use of licensing terms that only allow free redistribution of key components as a part of a greater ensemble has let to the systematic release of self-sufficient applications with built-in copies of external components.</p> </div> <div class="paragraph"> <p>As a consequence applications are only tested with the versions of the components they bundle, a complete Java system suffers from endless duplication of the same modules, and integrating multiple parts can be a nightmare since they are bound to depend on the same elements - only with different and subtly incompatible versions (different requirements, different bugs). Any security or compatibility upgrade must be performed for each of those duplicated elements.</p> </div> <div class="paragraph"> <p>This problem is compounded by the current practice of folding extensions in the JVM itself after a while; an element that could safely be embedded in a application will suddenly conflict with a JVM part and cause subtle failures.</p> </div> <div class="paragraph"> <p>It is not surprising then that complex Java systems tend to fossilize very quickly, with the cost of maintaining dependencies current growing too high so fast people basically give up on it.</p> </div> <div class="paragraph"> <p>This situation is incompatible with typical fast-evolving Linux platform. To attain the aim of user- and administrator-friendly RPM packaging of Java applications a custom infrastructure and strict packaging rules had to be evolved.</p> </div> <div class="sect2"> <h3 id="_basic_introduction_to_packaging_reasons_problems_rationale"><a class="anchor" href="#_basic_introduction_to_packaging_reasons_problems_rationale"></a>1.1. Basic introduction to packaging, reasons, problems, rationale</h3> <div class="paragraph"> <p>This section includes basic introduction to Java packaging world to people coming from different backgrounds. The goal is to understand language of all groups involved. If you are a Java developer coming into contact with RPM packaging for the first time start reading <a href="#_for_java_developers">Java developer</a> section. On the other hand if you are coming from RPM packaging background an <a href="#_for_packagers">introduction to Java world</a> is probably a better starting point.</p> </div> <div class="paragraph"> <p>It should be noted that especially in this section we might sacrifice correctness for simplicity.</p> </div> </div> <div class="sect2"> <h3 id="_for_packagers"><a class="anchor" href="#_for_packagers"></a>1.2. For Packagers</h3> <div class="paragraph"> <p>Java is a programming language which is usually compiled into bytecode for JVM (Java Virtual Machine). For more details about the JVM and bytecode specification see <a href="http://docs.oracle.com/javase/specs/jvms/se8/html/index.html">JVM documentation</a>.</p> </div> <div class="sect3"> <h4 id="_example_java_project"><a class="anchor" href="#_example_java_project"></a>1.2.1. Example Java Project</h4> <div class="paragraph"> <p>To better illustrate various parts of Java packaging we will dissect simple Java <code>Hello world</code> application. Java sources are usually organized using directory hierarchies. Shared directory hierarchy creates a namespace called <code>package</code> in Java terminology. To understand naming mechanisms of Java <code>packages</code> see <a href="http://docs.oracle.com/javase/tutorial/java/package/namingpkgs.html">Java package naming conventions</a>.</p> </div> <div class="paragraph"> <p>Let’s create a simple hello world application that will execute following steps when run:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>Ask for a name.</p> </li> <li> <p>Print out <code>Hello World from</code> and the name from previous step.</p> </li> </ol> </div> <div class="paragraph"> <p>To illustrate certain points we artificially complicate things by creating:</p> </div> <div class="ulist"> <ul> <li> <p><code>Input</code> class used only for input of text from terminal.</p> </li> <li> <p><code>Output</code> class used only for output on terminal.</p> </li> <li> <p><code>HelloWorldApp</code> class used as main application.</p> </li> </ul> </div> <div class="listingblock"> <div class="title">Directory listing of example project</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ find . . ./Makefile ./src ./src/org ./src/org/fedoraproject ./src/org/fedoraproject/helloworld ./src/org/fedoraproject/helloworld/output ./src/org/fedoraproject/helloworld/output/Output.java ./src/org/fedoraproject/helloworld/input ./src/org/fedoraproject/helloworld/input/Input.java ./src/org/fedoraproject/helloworld/HelloWorld.java</code></pre> </div> </div> <div class="paragraph"> <p>In this project all packages are under <code>src/</code> directory hierarchy.</p> </div> <div class="listingblock"> <div class="title">HelloWorld.java listing</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">Unresolved directive in introduction_for_packagers.adoc - include::{EXAMPLE}java_project/src/org/fedoraproject/helloworld/HelloWorld.java[]</code></pre> </div> </div> <div class="listingblock"> <div class="title">Java packages</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">org/fedoraproject/helloworld/input/Input.java org/fedoraproject/helloworld/output/Output.java org/fedoraproject/helloworld/HelloWorld.java</code></pre> </div> </div> <div class="paragraph"> <p>Although the directory structure of our package is hierarchical, there is no real parent-child relationship between packages. Each package is therefore seen as independent. The above example makes use of three separate packages:</p> </div> <div class="ulist"> <ul> <li> <p><code>org.fedoraproject.helloworld.input</code></p> </li> <li> <p><code>org.fedoraproject.helloworld.output</code></p> </li> <li> <p><code>org.fedoraproject.helloworld</code></p> </li> </ul> </div> <div class="paragraph"> <p>Environment setup consists of two main parts:</p> </div> <div class="ulist"> <ul> <li> <p>Telling JVM which Java class contains <code>main()</code> method.</p> </li> <li> <p>Adding required JAR files on JVM classpath.</p> </li> </ul> </div> <div class="paragraph"> <div class="title">Compiling our project</div> <p>The sample project can be compiled to a bytecode by Java compiler. Java compiler can be typically invoked from command line by command <code>javac</code>.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">javac $(find -name '*.java')</code></pre> </div> </div> <div class="paragraph"> <p>For every <code>.java</code> file corresponding <code>.class</code> file will be created. The <code>.class</code> files contain Java bytecode which is meant to be executed on JVM.</p> </div> <div class="paragraph"> <p>One could put invocation of <code>javac</code> to Makefile and simplify the compilation a bit. It might be sufficient for such a simple project, but it would quickly become hard to build more complex projects with this approach. Java world knows several high-level build systems which can highly simplify building of Java projects. Among others, probably the most known are <a href="https://maven.apache.org/">Apache Maven</a> and <a href="https://ant.apache.org/">Apache Ant</a>.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p>See also <a href="#_maven">Maven</a> and <a href="#_ant">Ant</a> sections.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <div class="title">JAR files</div> <p>Having our application split across many <code>.class</code> files would not be very practical, so those <code>.class</code> files are assembled into ZIP files with specific layout and called JAR files. Most commonly these special ZIP files have <code>.jar</code> suffix, but other variations exist (<code>.war</code>, <code>.ear</code>). They contain:</p> </div> <div class="ulist"> <ul> <li> <p>Compiled bytecode of our project.</p> </li> <li> <p>Additional metadata stored in <code>META-INF/MANIFEST.MF</code> file.</p> </li> <li> <p>Resource files such as images or localisation data.</p> </li> <li> <p>Optionaly the source code of our project (called source JAR then).</p> </li> </ul> </div> <div class="paragraph"> <p>They can also contain additional bundled software which is something we do not want to have in packages. You can inspect the contents of given JAR file by extracting it. That can be done with following command:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">jar -xf something.jar</code></pre> </div> </div> <div class="paragraph"> <p>The detailed description of JAR file format is in the <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/jar/jar.html">JAR File Specification</a>.</p> </div> <div class="paragraph"> <div class="title">Classpath</div> <p>The classpath is a way of telling JVM where to look for user classes and 3rd party libraries. By default, only current directory is searched, all other locations need to be specified explicitly by setting up <code>CLASSPATH</code> environment variable, or via <code>-cp</code> (<code>-classpath</code>) option of the Java Virtual Machine.</p> </div> <div class="listingblock"> <div class="title">Setting the classpath</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">java -cp /usr/share/java/log4j.jar:/usr/share/java/junit.jar mypackage/MyClass.class CLASSPATH=/usr/share/java/log4j.jar:/usr/share/java/junit.jar java mypackage/MyClass.class</code></pre> </div> </div> <div class="paragraph"> <p>Please note that two JAR files are separated by colon in a classpath definition.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p>See <a href="https://docs.oracle.com/javase/8/docs/technotes/tools/windows/classpath.html">official documentation</a> for more information about classpath.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <div class="title">Wrapper scripts</div> <p>Classic compiled applications use dynamic linker to find dependencies (linked libraries), whereas dynamic languages such as Python, Ruby, Lua have predefined directories where they search for imported modules. JVM itself has no embedded knowledge of installation paths and thus no automatic way to resolve dependencies of Java projects. This means that all Java applications have to use wrapper shell scripts to setup the environment before invoking the JVM and running the application itself. Note that this is not necessary for libraries.</p> </div> </div> <div class="sect3"> <h4 id="_build_system_identification"><a class="anchor" href="#_build_system_identification"></a>1.2.2. Build System Identification</h4> <div class="paragraph"> <p>The build system used by upstream can be usually identified by looking at their configuration files, which reside in project directory structure, usually in its root or in specialized directories with names such as <code>build</code> or <code>make</code>.</p> </div> <div class="paragraph"> <div class="title">Maven</div> <p>Build managed by Apache Maven is configured by an XML file that is by default named <code>pom.xml</code>. In its simpler form it usually looks like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example.myproject</groupId> <artifactId>myproject</artifactId> <packaging>jar</packaging> <version>1.0</version> <name>myproject</name> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.1</version> <scope>test</scope> </dependency> </dependencies> </project></code></pre> </div> </div> <div class="paragraph"> <p>It describes project’s build process in a declarative way, without explicitly specifying exact steps needed to compile sources and assemble pieces together. It also specifies project’s dependencies which are usually the main point of interest for packagers. Another important feature of Maven that packagers should know about are plugins. Plugins extend Maven with some particular functionality, but unfortunately some of them may get in the way of packaging and need to be altered or removed. There are RPM macros provided to facilitate modifying Maven dependencies and plugins.</p> </div> <div class="paragraph"> <div class="title">Ant</div> <p>Apache Ant is also configured by an XML file. It is by convention named <code>build.xml</code> and in its simple form it looks like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-xml hljs" data-lang="xml"><project name="MyProject" default="dist" basedir="."> <property name="src" location="src"/> <property name="build" location="build"/> <property name="dist" location="dist"/> <target name="init" description="Create build directory"> <mkdir dir="${build}"/> </target> <target name="compile" depends="init" description="Compile the source"> <javac srcdir="${src}" destdir="${build}"/> </target> <target name="dist" depends="compile" description="Generate jar"> <mkdir dir="${dist}/lib"/> <jar jarfile="${dist}/myproject.jar" basedir="${build}"/> </target> <target name="clean" description="Clean build files"> <delete dir="${build}"/> <delete dir="${dist}"/> </target> </project></code></pre> </div> </div> <div class="paragraph"> <p>Ant build file consists mostly of targets, which are collections of steps needed to accomplish intended task. They usually depend on each other and are generally similar to Makefile targets. Available targets can be listed by invoking <code>ant -p</code> in project directory containing <code>build.xml</code> file. If the file is named differently than <code>build.xml</code> you have to tell Ant which file should be used by using <code>-f</code> option with the name of the actual build file.</p> </div> <div class="paragraph"> <p>Some projects that use Apache Ant also use Apache Ivy to simplify dependency handling. Ivy is capable of resolving and downloading artifacts from Maven repositories which are declaratively described in XML. Project usually contains one or more <code>ivy.xml</code> files specifying the module Maven coordinates and its dependencies. Ivy can also be used directly from Ant build files. To detect whether the project you wish to package is using Apache Ivy, look for files named <code>ivy.xml</code> or nodes in the <code>ivy</code> namespace in project’s build file.</p> </div> <div class="paragraph"> <div class="title">Make</div> <p>While unlikely, it is still possible that you encounter a project whose build is managed by plain old Makefiles. They contain a list of targets which consist of commands (marked with tab at the begining of line) and are invoked by <code>make</code> <em>target</em> or simply <code>make</code> to run the default target.</p> </div> </div> <div class="sect3"> <h4 id="_quiz_for_packagers"><a class="anchor" href="#_quiz_for_packagers"></a>1.2.3. Quiz for Packagers</h4> <div class="paragraph"> <p>At this point you should have enough knowledge about Java to start packaging. If you are not able to answer following questions return back to previous sections or ask experienced packagers for different explanations of given topics.</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>What is the difference between JVM and Java?</p> </li> <li> <p>What is a <code>CLASSPATH</code> environment variable and how can you use it?</p> </li> <li> <p>Name two typical Java build systems and how you can identify which one is being used</p> </li> <li> <p>What is the difference between <code>java</code> and <code>javac</code> comands?</p> </li> <li> <p>What are contents of a typical <code>JAR</code> file?</p> </li> <li> <p>What is a <code>pom.xml</code> file and what information it contains?</p> </li> <li> <p>How would you handle packaging software that contains <code>lib/junit4.jar</code> inside source tarball?</p> </li> <li> <p>Name at least three methods for bundling code in Java projects</p> </li> </ol> </div> </div> </div> <div class="sect2"> <h3 id="_for_java_developers"><a class="anchor" href="#_for_java_developers"></a>1.3. For Java Developers</h3> <div class="paragraph"> <p>Packaging Java software has specifics which we will try to cover in this section aimed at Java developers who are already familiar with Java language, JVM, classpath handling, Maven, <code>pom.xml</code> file structure and dependencies.</p> </div> <div class="paragraph"> <p>Instead we will focus on basic packaging tools and relationships between Java and RPM world. One of the most important questions is: What is the reason to package software in RPM (or other distribution-specific formats). There are several reasons for it, among others:</p> </div> <div class="ulist"> <ul> <li> <p>Unified way of installation of software for users of distribution regardless of upstream projects</p> </li> <li> <p>Verification of authenticity of software packages by signing them</p> </li> <li> <p>Simplified software updates</p> </li> <li> <p>Automatic handling of dependencies for users</p> </li> <li> <p>Common filesystem layout across distribution enforced by packaging standards</p> </li> <li> <p>Ability to administer, monitor and query packages installed on several machines through unified interfaces</p> </li> <li> <p>Distribution of additional metadata with the software itself such as licenses used, homepage for the project, changelogs and other information that users or administrators can find useful</p> </li> </ul> </div> <div class="sect3"> <h4 id="_example_rpm_project"><a class="anchor" href="#_example_rpm_project"></a>1.3.1. Example RPM Project</h4> <div class="paragraph"> <p>RPM uses <code>spec</code> files as recipes for building software packages. We will use it to package example project created in previous section. If you did not read it you do not need to; the file listing is available here and the rest is not necessary for this section.</p> </div> <div class="listingblock"> <div class="title">Directory listing</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">Makefile src src/org src/org/fedoraproject src/org/fedoraproject/helloworld src/org/fedoraproject/helloworld/output src/org/fedoraproject/helloworld/output/Output.java src/org/fedoraproject/helloworld/input src/org/fedoraproject/helloworld/input/Input.java src/org/fedoraproject/helloworld/HelloWorld.java</code></pre> </div> </div> <div class="paragraph"> <p>We packed the project directory into file <code>helloworld.tar.gz</code>.</p> </div> <div id="helloworld_spec" class="listingblock"> <div class="title">Example spec file</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-rpmspec hljs" data-lang="rpmspec">Unresolved directive in introduction_for_developers.adoc - include::{EXAMPLE}rpm_project/helloworld.spec[]</code></pre> </div> </div> <div class="paragraph"> <p>RPM <code>spec</code> files contain several basic sections:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1">Header, which contains: </dt> <dd> <div class="ulist"> <ul> <li> <p>Package metadata such as its name, version, release, license, …​</p> </li> <li> <p>A <code>Summary</code> with basic one-line summary of package contents.</p> </li> <li> <p>Package source URLs denoted with <code>Source0</code> to <code>SourceN</code> directives.</p> <div class="ulist"> <ul> <li> <p>Source files can then be referenced by <code>%SOURCE0</code> to <code>%SOURCEn</code>, which expand to actual paths to given files.</p> </li> <li> <p>In practice, the source URL shouldn’t point to a file in our filesystem, but to an upstream release on the web.</p> </li> </ul> </div> </li> <li> <p>Patches - using <code>Patch0</code> to <code>PatchN</code>.</p> </li> <li> <p>Project dependencies.</p> <div class="ulist"> <ul> <li> <p>Build dependencies specified by <code>BuildRequires</code>, which need to be determined manually.</p> </li> <li> <p>Run time dependencies will be detected automatically. If it fails, you have to specify them with <code>Requires</code>.</p> </li> <li> <p>More information on this topic can be found in the <a href="#_dependency_handling">dependency handling</a> section.</p> </li> </ul> </div> </li> </ul> </div> </dd> <dt class="hdlist1"><code>%description</code></dt> <dd> <div class="ulist"> <ul> <li> <p>Few sentences about the project and its uses. It will be displayed by package management software.</p> </li> </ul> </div> </dd> <dt class="hdlist1"><code>%prep</code> section</dt> <dd> <div class="ulist"> <ul> <li> <p>Unpacks the sources using <code>setup -q</code> or manually if needed.</p> </li> <li> <p>If a source file doesn’t need to be extracted, it can be copied to build directory by <code>cp -p %SOURCE0 .</code>.</p> </li> <li> <p>Apply patches with <code>%patch X</code>, where <code>X</code> is the number of patch you want to apply. (You usually need the patch index, so it would be: <code>%patch 0 -p1</code>).</p> </li> </ul> </div> </dd> <dt class="hdlist1"><code>%build</code> section</dt> <dd> <div class="ulist"> <ul> <li> <p>Contains project compilation instructions. Usually consists of calling the projects build system such as Ant, Maven or Make.</p> </li> </ul> </div> </dd> <dt class="hdlist1">Optional <code>%check</code> section</dt> <dd> <div class="ulist"> <ul> <li> <p>Runs projects integration tests. Unit test are usually run in <code>%build</code> section, so if there are no integration tests available, this section is omitted.</p> </li> </ul> </div> </dd> <dt class="hdlist1"><code>%install</code> section</dt> <dd> <div class="ulist"> <ul> <li> <p>Copies built files that are supposed to be installed into <code>%{buildroot}</code> directory, which represents target filesystem’s root.</p> </li> </ul> </div> </dd> <dt class="hdlist1"><code>%files</code> section</dt> <dd> <div class="ulist"> <ul> <li> <p>Lists all files, that should be installed from <code>%{buildroot}</code> to target system.</p> </li> <li> <p>Documentation files are prefixed by <code>%doc</code> and are taken from build directory instead of buildroot.</p> </li> <li> <p>Directories that this package should own are prefixed with <code>%dir</code>.</p> </li> </ul> </div> </dd> <dt class="hdlist1"><code>%changelog</code></dt> <dd> <div class="ulist"> <ul> <li> <p>Contains changes to this spec file (not upstream).</p> </li> <li> <p>Has prescribed format. To prevent mistakes in format, it is advised to use tool such as <code>rpmdev-bumpspec</code> from package rpmdevtools to append new changelog entries instead of editing it by hand.</p> </li> </ul> </div> </dd> </dl> </div> <div class="paragraph"> <p>To build RPM from <a href="#helloworld_spec">this <code>spec</code> file</a> save it in your current directory and run <code>rpmbuild</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ rpmbuild -bb helloworld.spec</code></pre> </div> </div> <div class="paragraph"> <p>If everything worked OK, this should produce RPM file <code>~/rpmbuild/RPMS/x86_64/helloworld-1.0-1.fc18.x86_64.rpm</code>. You can use <code>rpm -i</code> or <code>dnf install</code> commands to install this package and it will add <code>/usr/share/java/helloworld.jar</code> and <code>/usr/bin/helloworld</code> wrapper script to your system. Please note that this specfile is simplified and lacks some additional parts, such as license installation.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>Paths and filenames might be slightly different depending on your architecture and distribution. Output of the commands will tell you exact paths.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>As you can see to build RPM files you can use <code>rpmbuild</code> command. It has several other options, which we will cover later on.</p> </div> <div class="paragraph"> <p>Other than building binary RPMs (<code>-bb</code>), <code>rpmbuild</code> can also be used to:</p> </div> <div class="ulist"> <ul> <li> <p>build only source RPMs (SRPMs), the packages containing source files which can be later build to RPMs (option <code>-bs</code>)</p> </li> <li> <p>build all, both binary and source RPMs (option <code>-ba</code>)</p> </li> </ul> </div> <div class="paragraph"> <p>See <code>rpmbuild</code> 's manual page for all available options.</p> </div> </div> <div class="sect3"> <h4 id="_querying_repositories"><a class="anchor" href="#_querying_repositories"></a>1.3.2. Querying repositories</h4> <div class="paragraph"> <p>Fedora comes with several useful tools which can provide great assistance in getting information from RPM repositories.</p> </div> <div class="paragraph"> <p><code>dnf repoquery</code> is a tool for querying information from RPM repositories. Maintainers of Java packages might typically query the repository for information like "which package contains the Maven artifact <code>groupId:artifactId</code>".</p> </div> <div class="listingblock"> <div class="title">Find out which package provides given artifact</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ dnf repoquery --whatprovides 'mvn(commons-io:commons-io)' apache-commons-io-1:2.4-9.fc19.noarch</code></pre> </div> </div> <div class="paragraph"> <p>The example above shows that one can get to <code>commons-io:commons-io</code> artifact by installing <code>apache-commons-io</code> package.</p> </div> <div class="paragraph"> <p>By default, <code>dnf repoquery</code> uses all enabled repositories in DNF configuration, but it is possible to explicitly specify any other repository. For example following command will query only Rawhide repository:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ dnf repoquery --available --disablerepo \* --enablerepo rawhide --whatprovides 'mvn(commons-io:commons-io)' apache-commons-io-1:2.4-10.fc20.noarch</code></pre> </div> </div> <div class="paragraph"> <p>Sometimes it may be useful to just list all the artifacts provided by given package:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ dnf repoquery --provides apache-commons-io apache-commons-io = 1:2.4-9.fc19 jakarta-commons-io = 1:2.4-9.fc19 mvn(commons-io:commons-io) = 2.4 mvn(org.apache.commons:commons-io) = 2.4 osgi(org.apache.commons.io) = 2.4.0</code></pre> </div> </div> <div class="paragraph"> <p>Output above means that package <code>apache-commons-io</code> provides two Maven artifacts: previously mentioned <code>commons-io:commons-io</code> and <code>org.apache.commons:commons-io</code>. In this case the second one is just an alias for same JAR file. See section about <a href="#_aliases">artifact aliases</a> for more information on this topic.</p> </div> <div class="paragraph"> <p>Another useful tool is <code>rpm</code>. It can do a lot of stuff, but most importantly it can replace <code>dnf repoquery</code> if one only needs to query local RPM database. Only installed packages, or local <code>.rpm</code> files, can be queried with this tool.</p> </div> <div class="paragraph"> <p>Common use case could be checking which Maven artifacts provide locally built packages.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ rpm -qp --provides simplemaven-1.0-2.fc21.noarch.rpm mvn(com.example:simplemaven) = 1.0 mvn(simplemaven:simplemaven) = 1.0 simplemaven = 1.0-2.fc21</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_quiz_for_java_developers"><a class="anchor" href="#_quiz_for_java_developers"></a>1.3.3. Quiz for Java Developers</h4> <div class="olist arabic"> <ol class="arabic"> <li> <p>How would you build a binary RPM if you were given a source RPM?</p> </li> <li> <p>What is most common content of <code>Source0</code> <code>spec</code> file tag?</p> </li> <li> <p>What is the difference between <code>Version</code> and <code>Release</code> tags?</p> </li> <li> <p>How would you apply a patch in RPM?</p> </li> <li> <p>Where on filesystem should JAR files go?</p> </li> <li> <p>What is the format of RPM changelog or what tool would you use to produce it?</p> </li> <li> <p>How would you install an application that needs certain layout (think <code>ANT_HOME</code>) while honoring distribution filesystem layout guidelines?</p> </li> <li> <p>How would you generate script for running a application with main class <code>org.project.MainClass</code> which depends on <code>commons-lang</code> jar?</p> </li> </ol> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_java_specifics_in_fedora_for_users_and_developers"><a class="anchor" href="#_java_specifics_in_fedora_for_users_and_developers"></a>2. Java Specifics in Fedora for Users and Developers</h2> <div class="sectionbody"> <div class="paragraph"> <p>This section contains information about default Java implementation in Fedora, switching between different Java runtime environments and about few useful tools which can be used during packaging / development.</p> </div> <div class="sect2"> <h3 id="_java_implementation_in_fedora"><a class="anchor" href="#_java_implementation_in_fedora"></a>2.1. Java implementation in Fedora</h3> <div class="paragraph"> <p>Fedora ships with an open-source reference implementation of Java Standard Edition called <a href="https://openjdk.java.net/">OpenJDK</a>. OpenJDK provides Java Runtime Environment for Java applications and set of development tools for Java developers.</p> </div> <div class="paragraph"> <p>From users point of view, <code>java</code> command is probably the most interesting. It is a Java application launcher which spawns Java Virtual Machine (JVM), loads specified <code>.class</code> file and executes its main method.</p> </div> <div class="paragraph"> <p>Here is an example how to run sample Java project from section <a href="#_example_java_project">Example Java Project</a>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ java org/fedoraproject/helloworld/HelloWorld.class</code></pre> </div> </div> <div class="paragraph"> <p>OpenJDK provides a lot of interesting tools for Java developers:</p> </div> <div class="ulist"> <ul> <li> <p><code>javac</code> is a Java compiler which translates source files to Java bytecode, which can be later interpreted by JVM.</p> </li> <li> <p><code>jdb</code> is a simple command-line debugger for Java applications.</p> </li> <li> <p><code>javadoc</code> is a tool for generating Javadoc documentation.</p> </li> <li> <p><code>javap</code> can be used for disassembling Java class files.</p> </li> </ul> </div> <div class="sect3"> <h4 id="_switching_between_different_java_implementations"><a class="anchor" href="#_switching_between_different_java_implementations"></a>2.1.1. Switching between different Java implementations</h4> <div class="paragraph"> <p>Users and developers may want to have multiple Java environments installed at the same time. It is possible in Fedora, but only one of them can be default Java environment in system. Fedora uses <code>alternatives</code> for switching between different installed JREs/JDKs.</p> </div> <div class="listingblock"> <div class="content"> <pre class="nowrap"># alternatives --config java There are 3 programs which provide 'java'. Selection Command ----------------------------------------------- 1 java-17-openjdk.x86_64 (/usr/lib/jvm/java-17-openjdk-17.0.2.0.8-1.fc35.x86_64/bin/java) *+ 2 java-11-openjdk.x86_64 (/usr/lib/jvm/java-11-openjdk-11.0.14.1.1-5.fc35.x86_64/bin/java) 3 java-latest-openjdk.x86_64 (/usr/lib/jvm/java-18-openjdk-18.0.1.0.10-1.rolling.fc35.x86_64/bin/java) Enter to keep the current selection[+], or type selection number:</pre> </div> </div> <div class="paragraph"> <p>Example above shows how to chose default Java environment. <code>java</code> command will then point to the Java implementation provided by given JRE.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p>See <code>man alternatives</code> for more information on how to use <code>alternatives</code>.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Developers may want to use Java compiler from different JDK. This can be achieved with <code>alternatives --config javac</code>.</p> </div> </div> </div> <div class="sect2"> <h3 id="_building_classpath_with_build_classpath"><a class="anchor" href="#_building_classpath_with_build_classpath"></a>2.2. Building classpath with <code>build-classpath</code></h3> <div class="paragraph"> <p>Most of the Java application needs to specify classpath in order to work correctly. Fedora contains several tools which make working with classpaths easier.</p> </div> <div class="paragraph"> <p><code>build-classpath</code> - this tool takes JAR filenames or artifact coordinates as arguments and translates them to classpath-like string. See the following example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ build-classpath log4j junit org.ow2.asm:asm /usr/share/java/log4j.jar:/usr/share/java/junit.jar:/usr/share/java/objectweb-asm4/asm.jar</code></pre> </div> </div> <div class="paragraph"> <p><code>log4j</code> corresponds to <code>log4j.jar</code> stored in <code>%{_javadir}</code>. If the JAR file is stored in subdirectory under <code>%{_javadir}</code>, it is neccessary to pass <code>subdirectory/jarname</code> as an argument to <code>build-classpath</code>. Example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ build-classpath httpcomponents/httpclient.jar /usr/share/java/httpcomponents/httpclient.jar</code></pre> </div> </div> </div> <div class="sect2"> <h3 id="_building_jar_repository_with_build_jar_repository"><a class="anchor" href="#_building_jar_repository_with_build_jar_repository"></a>2.3. Building JAR repository with <code>build-jar-repository</code></h3> <div class="paragraph"> <p>Another tool is <code>build-jar-repository</code>. It can fill specified directory with symbolic / hard links to specified JAR files. Similarly to <code>build-classpath</code>, JARs can be identified by their names or artifact coordintes.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ build-jar-repository my-repo log4j httpcomponents/httpclient junit:junit $ ls -l my-repo/ total 0 lrwxrwxrwx. 1 msrb msrb 45 Oct 29 10:39 [httpcomponents][httpclient].jar -> /usr/share/java/httpcomponents/httpclient.jar lrwxrwxrwx. 1 msrb msrb 25 Oct 29 10:39 [junit:junit].jar -> /usr/share/java/junit.jar lrwxrwxrwx. 1 msrb msrb 25 Oct 29 10:39 [log4j].jar -> /usr/share/java/log4j.jar</code></pre> </div> </div> <div class="paragraph"> <p>Similar command <code>rebuild-jar-repository</code> can be used to rebuild JAR repository previously built by <code>build-jar-repository</code>. See <code>man rebuild-jar-repository</code> for more information.</p> </div> <div class="paragraph"> <p><code>build-classpath-directory</code> is a small tool which can be used to build classpath string from specified directory.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ build-classpath-directory /usr/share/java/xstream /usr/share/java/xstream/xstream-benchmark.jar:/usr/share/java/xstream/xstream.jar :/usr/share/java/xstream/xstream-hibernate.jar</code></pre> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_java_specifics_in_fedora_for_packagers"><a class="anchor" href="#_java_specifics_in_fedora_for_packagers"></a>3. Java Specifics in Fedora for Packagers</h2> <div class="sectionbody"> <div class="sect2"> <h3 id="_directory_layout"><a class="anchor" href="#_directory_layout"></a>3.1. Directory Layout</h3> <div class="paragraph"> <p>This section describes most of directories used for Java packaging. Each directory is named in RPM macro form, which shows how it should be used in RPM spec files. Symbolic name is followed by usual macro expansion (i.e. physical directory location in the file system) and short description.</p> </div> <div class="dlist glossary"> <div class="title">Directories commonly used by regular packages</div> <dl> <dt><code>%{_javadir}</code> — <code>/usr/share/java</code></dt> <dd> <p>Directory that holds all JAR files that do not contain or use native code and do not depend on a particular Java standard version. JAR files can either be placed directly in this directory or one of its subdirectories. Often packages create their own subdirectories there, in this case subdirectory name should match package name.</p> </dd> <dt><code>%{_jnidir}</code> — <code>/usr/lib/java</code></dt> <dd> <p>Directory where architecture-specific JAR files are installed. In particular, JAR files containing or using native code (Java Native Interface, JNI) should be installed there.</p> </dd> <dt><code>%{_javadocdir}</code> — <code>/usr/share/javadoc</code></dt> <dd> <p>Root directory where all Java API documentation (Javadoc) is installed. Each source package usually creates a single subdirectory containing aggregated Javadocs for all binary packages it produces.</p> </dd> <dt><code>%{_mavenpomdir}</code> — <code>/usr/share/maven-poms</code></dt> <dd> <p>Directory where Project Object Model (POM) files used by Apache Maven are installed. Each POM must have name that strictly corresponds to JAR file in <code>%{_javadir}</code> or <code>%{_jnidir}</code>.</p> </dd> <dt><code>%{_ivyxmldir}</code> — <code>/usr/share/ivy-xmls</code></dt> <dd> <p>Directory where <code>ivy.xml</code> files used by Apache Ivy are installed. Each XML must have name that strictly corresponds to JAR file in <code>%{_javadir}</code> or <code>%{_jnidir}</code>.</p> </dd> </dl> </div> <div class="dlist glossary"> <div class="title">Other directories</div> <dl> <dt><code>%{_jvmdir}</code> — <code>/usr/lib/jvm</code></dt> <dd> <p>Root directory where different Java Virtual Machines (JVM) are installed. Each JVM creates a subdirectory, possibly with several alternative names implemented with symbolic links. Directories prefixed with <code>java</code> contain Java Development Kit (JDK), while directories which names start with <code>jre</code> hold Java Runtime Environment (JRE).</p> </dd> <dt><code>%{_jvmsysconfdir}</code> — <code>/etc/jvm</code></dt> <dt><code>%{_jvmcommonsysconfdir}</code> — <code>/etc/jvm-common</code></dt> <dd> <p>Directories containing configuration files for Java Virtual Machines (JVM).</p> </dd> <dt><code>%{_jvmprivdir}</code> — <code>/usr/lib/jvm-private</code></dt> <dt><code>%{_jvmlibdir}</code> — <code>/usr/lib/jvm</code></dt> <dt><code>%{_jvmdatadir}</code> — <code>/usr/share/jvm</code></dt> <dt><code>%{_jvmcommonlibdir}</code> — <code>/usr/lib/jvm-common</code></dt> <dt><code>%{_jvmcommondatadir}</code> — <code>/usr/share/jvm-common</code></dt> <dd> <p>Directories containing implementation files of Java Virtual Machines (JVM). Describing them in detail is out of scope for this document. Purpose of each directory is commented briefly in <code>macros.jpackage</code> file in <code>/etc/rpm</code>. More detailed description can be found in JPackage policy.</p> </dd> <dt><code>%{_javaconfdir}</code> — <code>/etc/java</code></dt> <dd> <p>Directory containing Java configuration files. In particular it contains main Java configuration file — <code>java.conf</code>.</p> </dd> </dl> </div> </div> <div class="sect2"> <h3 id="_jar_file_identification"><a class="anchor" href="#_jar_file_identification"></a>3.2. JAR File Identification</h3> <div class="paragraph"> <p>Complex Java applications usually consist of multiple components. Each component can have multiple implementations, called <em>artifacts</em>. Artifacts in Java context are <em>usually</em> JAR files, but can also be WAR files or any other kind of file.</p> </div> <div class="paragraph"> <p>There are multiple incompatible ways of identifying (naming) Java artifacts and each build system often encourages usage of specific naming scheme. This means that Linux distributions also need to allow each artifact to be located using several different identifiers, possible using different schemes. On the other hand it is virtually impossible to every naming scheme, so there are some simplifications.</p> </div> <div class="paragraph"> <p>This chapter describes artifact different ways to identify and locate artifacts in system repository.</p> </div> <div class="sect3"> <h4 id="_relative_paths"><a class="anchor" href="#_relative_paths"></a>3.2.1. Relative paths</h4> <div class="paragraph"> <p>JAR artifacts are installed in one of standard directory trees. Usually this is either <code>%{_javadir}</code> (<code>/usr/share/java</code>) or <code>%{_jnidir}</code> (<code>/usr/lib/java</code>).</p> </div> <div class="paragraph"> <p>The simplest way of identifying artifacts is using their relative path from one of standard locations. All artifact can be identified this way because each artifacts has a unique file name. Each path identifying artifact will be called <em>artifact path</em> in this document.</p> </div> <div class="paragraph"> <p>To keep artifact paths simpler and more readable, extension can be omitted if it is equal to <code>jar</code>. For non-JAR artifacts extension cannot be omitted and must be retained.</p> </div> <div class="paragraph"> <p>Additionally, if artifact path points to a directory then it represents all artifacts contained in this directory. This allows a whole set of related artifacts to be referenced easily by specifying directory name containing all of them.</p> </div> <div class="paragraph"> <p>If the same artifact path has valid expansions in two different root directories then it is unspecified which artifacts will be located.</p> </div> </div> <div class="sect3"> <h4 id="_artifact_specification"><a class="anchor" href="#_artifact_specification"></a>3.2.2. Artifact specification</h4> <div class="paragraph"> <p>As noted in previous section, every artifact can be uniquely identified by its file path. However this is not always the preferred way of artifact identification.</p> </div> <div class="paragraph"> <p>Modern Java build systems provide a way of identifying artifacts with an abstract identifier, or more often, a pair of identifiers. The first if usually called <strong>group ID</strong> or <strong>organization ID</strong> while the second is just <strong>artifact ID</strong>. This pair of identifiers will be called <strong>artifact coordinates</strong> in this document. Besides group ID and artifact ID, artifact coordinates may also include other optional information about artifact, such as <strong>extension</strong>, <strong>classifier</strong> and <strong>version</strong>.</p> </div> <div class="paragraph"> <p>In Linux distributions it is important to stay close to upstreams providing software being packaged, so the ability to identify artifacts in the same way as upstream does is very important from the packaging point of view. Every artifact can optionally be identified by artifact coordinates assigned during package build. Packages built with Maven automatically use this feature, but all other packages, even these built with pure <code>javac</code>, can use this feature too (see description of <a href="#_installing_additional_artifacts"><code>%mvn_artifact</code></a> and <a href="#_add_maven_depmap_macro"><code>%add_maven_depmap</code></a> macros).</p> </div> </div> <div class="sect3"> <h4 id="_aliases"><a class="anchor" href="#_aliases"></a>3.2.3. Aliases</h4> <div class="paragraph"> <p>Aliases working in two ways:</p> </div> <div class="ulist"> <ul> <li> <p>Symlinks for paths</p> </li> <li> <p>Additional mappings for artifact specifications</p> </li> </ul> </div> <div class="paragraph"> <p>In the real world the same project can appear under different names as it was evolving or released differently. Therefore other projects may refer to those alternative names instead of using the name currently prefered by upstream.</p> </div> <div class="sect4"> <h5 id="_artifact_aliases"><a class="anchor" href="#_artifact_aliases"></a>Artifact aliases</h5> <div class="paragraph"> <p>XMvn provides a way to attach multiple artifact coordinates to a single artifact. Dependent projects that use alternative coordinates can then be built without the need to patch their POMs or alter the build by other means. It will also generate virtual provides for the alias, so it can be also used in <code>Requires</code> and <code>BuildRequires</code>. Creating an alias is achieved by <code>%mvn_alias</code> macro.</p> </div> <div class="listingblock"> <div class="title">Example invocation</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell"># com.example.foo:bar (the actual artifact existing in the project) will also # be available as com.example.foo:bar-all %mvn_alias com.example.foo:bar com.example.foo:bar-all # You don't need to repeat the part of coordinates that stays the same # (groupID in this case) %mvn_alias com.example.foo:bar :bar-all # You can specify multiple aliases at once %mvn_alias com.example.foo:bar :bar-all :bar-lib # The macro supports several shortcuts to generate multiple alisaes. # Braces - {} - capture their content, which can then be referenced in the # alias part with @N, where N is the index of the capture group. # * acts as a wildcard (matching anything) # The following generates aliases ending with shaded for all artifacts in the # project %mvn_alias 'com.example.foo:{*}' :@1-shaded</code></pre> </div> </div> </div> </div> <div class="sect3"> <h4 id="_compatibility_versions"><a class="anchor" href="#_compatibility_versions"></a>3.2.4. Compatibility versions</h4> <div class="paragraph"> <p>Handling of compatibility packages, versioned jars etc.</p> </div> <div class="paragraph"> <p>In Fedora we prefer to always have only the latest version of a given project. Unfortunately, this is not always possible as some projects change too much and it would be too hard to port dependent packages to the current version. It is not possible to just update the package and keep the old version around as the names, file paths and dependency provides would clash. The recommended practice is to update the current package to the new version and create new package representing the old version (called compat package). The compat package needs to have the version number (usually only the major number, unless further distinction is necessary) appended to the name, thus effectivelly having different name from RPM’s point of view. Such compat package needs to perform some additional steps to ensure that it can be installed and used along the non-compat one.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>You should always evaluate whether creating a compat package is really necessary. Porting dependent projects to new versions of dependencies may be a complicated task, but your effort would be appreciated and it is likely that the patch will be accepted upstream at some point in time. If the upstream is already inactive and the package is not required by anything, you should also consider retiring it.</p> </div> </td> </tr> </table> </div> <div class="sect4"> <h5 id="_maven_compat_versions"><a class="anchor" href="#_maven_compat_versions"></a>Maven Compat Versions</h5> <div class="paragraph"> <p>XMvn supports marking particular artifact as compat, performing the necessary steps to avoid clashes with the non-compat version. An artifact can be marked as compat by <code>%mvn_compat_version</code>. It accepts an artifact argument which will determine which artifact will be compat. The format for specifying artifact coordinates is the same as with <a href="#_mvn_alias"><code>%mvn_alias</code></a>. In the common case you will want to mark all artifacts as compat. You can specify multiple compat versions at a time.</p> </div> <div class="paragraph"> <div class="title">Dependency resolution of compat artifacts</div> <p>When XMvn performs dependency resolution for a dependency artifact in a project, it checks the dependency version and compares it against all versions of the artifact installed in the buildroot. If none of the compat artifacts matches it will resolve the artifact to the non-compat one. This has a few implications:</p> </div> <div class="ulist"> <ul> <li> <p>The versions are compared for exact match. The compat package should provide all applicable versions that are present in packages that are supposed to be used with this version.</p> </li> <li> <p>The dependent packages need to have correct <code>BuildRequires</code> on the compat package as the virtual provides is also different (see below).</p> </li> </ul> </div> <div class="paragraph"> <div class="title">File names and virtual provides</div> <p>In order to prevent file name clashes, compat artifacts have the first specified compat version appended to the filename. Virtual provides for compat artifacts also contain the version as the last part of the coordinates. There are multiple provides for each specified compat version. Non-compat artifact do not have any version in the virtual provides.</p> </div> <div class="listingblock"> <div class="title">Example invocation of <code>%mvn_compat_version</code></div> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell"># Assuming the package has name bar and version 3 # Sets the compat version of foo:bar artifact to 3 %mvn_compat_version foo:bar 3 # The installed artifact file (assuming it's jar and there were no # %mvn_file calls) will be at %{_javadir}/bar/bar-3.jar # The generated provides for foo:bar will be # mvn(foo:bar:3) = 3 # mvn(foo:bar:pom:3) = 3 # Sets the compat versions of all artifacts in the build to 3 and 3.2 %mvn_compat_version : 3 3.2</code></pre> </div> </div> </div> </div> </div> <div class="sect2"> <h3 id="_dependency_handling"><a class="anchor" href="#_dependency_handling"></a>3.3. Dependency Handling</h3> <div class="paragraph"> <p>RPM has multiple types of metadata to describe dependency relationships between packages. The two basic types are <code>Requires</code> and <code>Provides</code>. <code>Requires</code> denote that a package needs something to be present at runtime to work correctly and the package manager is supposed to ensure that requires are met. A single <code>Requires</code> item can specify a package or a virtual provide. RPM <code>Provides</code> are a way to express that a package provides certain capability that other packages might need. In case of Maven packages, the <code>Provides</code> are used to denote that a package contains certain Maven artifact. They add more flexibility to the dependency management as single package can have any number of provides, and they can be moved across different packages without breaking other packages' requires. <code>Provides</code> are usually generated by automatic tools based on the information from the built binaries or package source.</p> </div> <div class="paragraph"> <div class="title">Dependency handling for Maven packages</div> <p>The Java packaging tooling on Fedora provides automatic <code>Requires</code> and <code>Provides</code> generation for packages built using XMvn. The <code>Provides</code> are based on Maven artifact coordinates of artifacts that were installed by the currently being built. They are generated for each subpackage separately. They follow a general format <code>mvn(groupId:artifactId:extension:classifier:version)</code>, where the extension is omitted if its <code>jar</code> and classifier is omitted if empty. <code>Version</code> is present only for compat artifacts, but the trailing colon has to be present unless it is a Jar artifact with no classifier.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell"># Example provide for Jar artifact mvn(org.eclipse.jetty:jetty-server) # Example provide for POM artifact mvn(org.eclipse.jetty:jetty-parent:pom:) # Example provide for Jar artifact with classifier mvn(org.sonatype.sisu:sisu-guice::no_aop:)</code></pre> </div> </div> <div class="paragraph"> <p>The generated Requires are based on dependencies specified in Maven POMs in the project. Only dependencies with <code>scope</code> set to either <code>compile</code>, <code>runtime</code> or not set at all are used for Requires generation. Requires do not rely on package names and instead always use virtual provides that were described above, in exactly the same format, in order to be satisfiable by the already existing provides. For packages consisting of multiple subpackages, <code>Requires</code> are generated separately for each subpackage. Additionally, <code>Requires</code> that point to an artifact in a different subpackage of the same source package are generated with exact versions to prevent version mismatches between artifacts belonging to the same project.</p> </div> <div class="paragraph"> <p>The requires generator also always generates <code>Requires</code> on <code>java-headless</code> and <code>javapackages-tools</code>.</p> </div> <div class="paragraph"> <div class="title">Dependency handling for non-Maven packages that ship POM files</div> <p>If the package is built built using different tool than Apache Maven, but still ships Maven POM(s), the you will still get automatic provides generation if you install the POM using <code>%mvn_artifact</code> and <code>%mvn_install</code>. The requires generation will also be executed but the outcome largely depends on whether the POM contains accurate dependency insformation. If it contains dependency information, you should double-check that it is correct and up-to-date. Otherwise you need to add <code>Requires</code> tags manually as described in the next section.</p> </div> <div class="paragraph"> <div class="title">Dependency handling for non-Maven packages that don’t ship POM files</div> <p>For packages without POMs it is necessary to specify <code>Requires</code> tags manually. In order to build the package you needed to specify <code>BuildRequires</code> tags. Your <code>Requires</code> tags will therefore likely be a subset of your <code>BuildRequires</code>, excluding build tools and test only dependencies.</p> </div> <div class="paragraph"> <div class="title">Querying Requires and Provides of built packages</div> <p>The generated Requires and Provides of built packages can be queried using <code>rpm</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">rpm -qp --provides path/to/example-1.0.noarch.rpm rpm -qp --requires path/to/example-1.0.noarch.rpm</code></pre> </div> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p>See also <a href="#_querying_repositories">Querying Fedora repositories</a></p> </div> </td> </tr> </table> </div> <div class="paragraph"> <div class="title">Generating BuildRequires</div> <p>While <code>Requires</code> and <code>Provides</code> generation is automated for Maven projects, <code>BuildRequires</code> still remains a manual task. However, there are tools to simplify it to some extent. XMvn ships a script <code>xmvn-builddep</code> that takes a <code>build.log</code> output from mock and prints Maven-style <code>BuildRequires</code> on artifacts that were actually used during the build. It does not help you to figure out what the <code>BuildRequires</code> are before you actually build it, but it may help you to have a minimal set of <code>BuildRequires</code> that are less likely to break, as they do not rely on transitive dependencies.</p> </div> </div> <div class="sect2"> <h3 id="_javadoc_packages"><a class="anchor" href="#_javadoc_packages"></a>3.4. Javadoc packages</h3> <div class="paragraph"> <p>Javadoc subpackages in Fedora provide automatically generated API documentation for Java libraries and applications. <a href="#_java_implementation_in_fedora">Java Development Kit</a> comes with tool called <code>javadoc</code>. This tool can be used for generating the documentation from specially formated comments in Java source files. Output of this tool, together with license files, usually represents only content of javadoc subpackages. Note <code>javadoc</code> invocation is typically handled by build system and package maintainer does not need to deal with it directly.</p> </div> <div class="paragraph"> <p>Javadoc subpackage shouldn’t depend on its base package and vice versa. The rationale behind this rule is that documentation can usually be used independently from application / library and therefore base package does not need to be always installed. Users are given an option to install application and documentation separately.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p>You can learn more about <code>javadoc</code> from <a href="https://www.oracle.com/technetwork/java/javase/documentation/index-137868.html">official documentation</a>.</p> </div> </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="_core_java_packages"><a class="anchor" href="#_core_java_packages"></a>3.5. Core Java packages</h3> <div class="sect3"> <h4 id="_jvm"><a class="anchor" href="#_jvm"></a>3.5.1. JVM</h4> <div class="paragraph"> <p>Fedora allows multiple Java Virtual Machines (JVMs) to be packaged independently. Java packages should not directly depend on any particulat JVM, but instead require one of three virtual JVM packages depending of what Java funtionality is required.</p> </div> <div class="dlist"> <dl> <dt class="hdlist1"><strong><code>java-headless</code></strong></dt> <dd> <p>This package provides a working Java Runtime Environment (JRE) with some functionality disabled. Graphics and audio support may be unavailable in this case. <code>java-headless</code> provides functionality that is enough for most of packages and avoids pulling in a number of graphics and audio libraries as dependencies. Requirement on <code>java-headless</code> is appropriate for most of Java packages.</p> </dd> <dt class="hdlist1"><strong><code>java</code></strong></dt> <dd> <p>Includes the same base functionality as <code>java-headless</code>, but also implements audio and graphics subsystems. Packages should require <code>java</code> if they need some functionality from these subsystems, for example creating GUI using AWT library.</p> </dd> <dt class="hdlist1"><strong><code>java-devel</code></strong></dt> <dd> <p>Provides full Java Development Kit (JDK). In most cases only packages related to Java development should have runtime dependencies on <code>java-devel</code>. Runtime packages should require <code>java-headless</code> or <code>java</code>. Some packages not strictly related to java development need access to libraries included with JDK, but not with JRE (for example <code>tools.jar</code>). That is one of few cases where requiring <code>java-devel</code> may be necessary.</p> </dd> </dl> </div> <div class="paragraph"> <p>Packages that require minimal Java standard version can add versioned dependencies on one of virtual packages providing Java environment. For example if packages depending on functionality of JDK 8 can require <code>java-headless >= 1:1.8.0</code>.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="title">Epoch in versions of JVM packages</div> <div class="paragraph"> <p>For compatibility with JPackage project packages providing Java 1.6.0 or later use epoch equal to <code>1</code>. This was necessary because package <code>java-1.5.0-ibm</code> from JPackage project had epoch <code>1</code> for some reason. Therefore packages providing other implementations of JVM also had to use non-zero epoch in order to keep version ordering correct.</p> </div> </td> </tr> </table> </div> </div> <div class="sect3"> <h4 id="_java_packages_tools"><a class="anchor" href="#_java_packages_tools"></a>3.5.2. Java Packages Tools</h4> <div class="paragraph"> <p>Java Packages Tools are packaged as several binary RPM packages:</p> </div> <div class="dlist"> <dl> <dt class="hdlist1"><strong><code>maven-local</code></strong></dt> <dd> <p>This package provides a complete environment which is required to build Java packages using Apache Maven build system. This includes a default system version of Java Development Kit (JDK), Maven, a number of Maven plugins commonly used to build packages, various macros and utlilty tools. <code>maven-local</code> is usually declared as build dependency of Maven packages.</p> </dd> <dt class="hdlist1"><strong><code>ivy-local</code></strong></dt> <dd> <p>Analogously to <code>maven-local</code>, this package provides an environment required to build Java packages using Apache Ivy as dependency manager.</p> </dd> <dt class="hdlist1"><strong><code>javapackages-local</code></strong></dt> <dd> <p>Package providing a basic environment necessary to geterate and install metadata for system artifact repository.</p> </dd> <dt class="hdlist1"><strong><code>javapackages-tools</code></strong></dt> <dd> <p>Package owning basic Java directories and providing runtime support for Java packages. The great majority of Java packages depend on <code>javapackages-tools</code>.</p> </dd> </dl> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_packaging_best_practices"><a class="anchor" href="#_packaging_best_practices"></a>4. Packaging Best Practices</h2> <div class="sectionbody"> <div class="paragraph"> <p>Packaging Java has certain specifics that will be covered in this section which will cover basic packaging principles:</p> </div> <div class="ulist"> <ul> <li> <p>No bundling</p> </li> <li> <p>Working with upstreams</p> </li> <li> <p>Commenting workarounds</p> </li> <li> <p>Single library version</p> </li> <li> <p>Links to other appropriate documents</p> </li> <li> <p>…​</p> </li> </ul> </div> </div> </div> <div class="sect1"> <h2 id="_generic_java_builds"><a class="anchor" href="#_generic_java_builds"></a>5. Generic Java Builds</h2> <div class="sectionbody"> <div class="paragraph"> <p>This chapter talks about basic build steps in Java such as invoking <code>javac</code> and using spec macros like <code>build-claspath</code> and <code>build-jar-repository</code>.</p> </div> <div class="sect2"> <h3 id="_generating_application_shell_scripts"><a class="anchor" href="#_generating_application_shell_scripts"></a>5.1. Generating Application Shell Scripts</h3> <div class="paragraph"> <p>As mentioned in section about <a href="#_for_packagers">Java packaging basics</a>, all Java applications need wrapper shell scripts to setup the environment before running JVM and associated Java code.</p> </div> <div class="paragraph"> <p>The <code>javapackages-tools</code> package contains a convenience <code>%jpackage_script</code> macro that can be used to create scripts that work for the majority of packages. See its definition and documentation in <code>/usr/lib/rpm/macros.d/macros.jpackage</code>. One thing to pay attention to is the 6th argument to it - whether to prefer a JRE over a full SDK when looking up a JVM to invoke. Most packages that do not require the full Java SDK will want to set that to <code>true</code> to avoid unexpected results when looking up a JVM when some of the installed JREs do not have the corresponding SDK (<code>*-devel</code> package) installed.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">%install ... %jpackage_script msv.textui.Driver "" "" msv-msv:msv-xsdlib:relaxngDatatype:isorelax msv true ...</code></pre> </div> </div> <div class="paragraph"> <p>The previous example installs the <code>msv</code> script (5th argument) with main class being <code>msv.textui.Driver</code> (1st argument). No optional flags (2nd argument) or options (3rd argument) are used. This script will add several libraries to classpath before executing main class (4th argument, JAR files separated with <code>:</code>). <code>build-classpath</code> is run on every part of 4th argument to create full classpaths.</p> </div> </div> <div class="sect2"> <h3 id="_replacing_jars_with_symlinks_using_xmvn_subst"><a class="anchor" href="#_replacing_jars_with_symlinks_using_xmvn_subst"></a>5.2. Replacing JARs with symlinks using <code>xmvn-subst</code></h3> <div class="paragraph"> <p>Sometimes it may be needed to replace all JAR files in current directory with symlinks to the system JARs located in <code>%{_javadir}</code>. This task can be achieved using tool called <code>xmvn-subst</code>.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ ls -l -rw-r--r--. 1 msrb msrb 40817 Oct 22 09:16 cli.jar -rw-r--r--. 1 msrb msrb 289983 Oct 22 09:17 junit4.jar -rw-r--r--. 1 msrb msrb 474276 Oct 22 09:14 log4j.jar $ xmvn-subst . [INFO] Linked ./cli.jar to /usr/share/java/commons-cli.jar [INFO] Linked ./log4j.jar to /usr/share/java/log4j.jar [INFO] Linked ./junit4.jar to /usr/share/java/junit.jar $ ls -la lrwxrwxrwx. 1 msrb msrb 22 Oct 22 10:08 cli.jar -> /usr/share/java/commons-cli.jar lrwxrwxrwx. 1 msrb msrb 22 Oct 22 10:08 junit4.jar -> /usr/share/java/junit.jar lrwxrwxrwx. 1 msrb msrb 22 Oct 22 10:08 log4j.jar -> /usr/share/java/log4j.jar</code></pre> </div> </div> <div class="paragraph"> <p>The example above shows how easy the symlinking can be. However, there are some limitations. Original JAR files need to carry metadata which tell <code>xmvn-subst</code> for what artifact given file should be substituted. Otherwise <code>xmvn-subst</code> won’t be able to identify the Maven artifact from JAR file.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p>See <code>xmvn-subst -h</code> for all available options.</p> </div> </td> </tr> </table> </div> </div> </div> </div> <div class="sect1"> <h2 id="_ant"><a class="anchor" href="#_ant"></a>6. Ant</h2> <div class="sectionbody"> <div class="quoteblock"> <blockquote> <div class="paragraph"> <p>Apache Ant is a Java library and command-line tool whose mission is to drive processes described in build files as targets and extension points dependent upon each other.</p> </div> </blockquote> <div class="attribution"> — https://ant.apache.org/ </div> </div> <div class="paragraph"> <p>Apache Ant is one of the most popular Java build tools after Apache Maven. The main difference between these two tools is that Ant is procedural and Maven is declarative. When using Ant, it is neccessary to exactly describe the processes which lead to the result. It means that one needs to specify where the source files are, what needs to be done and when it needs to be done. On the other hand, Maven relies on conventions and doesn’t require specifying most of the process unless you need to override the defaults.</p> </div> <div class="paragraph"> <p>If upstream ships a Maven POM file, it must be installed even if you don’t build with Maven. If not, you should try to search Maven Central Repository for it, ship it as another source and install it.</p> </div> <div class="listingblock"> <div class="title">Common spec file</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">BuildRequires: ant BuildRequires: javapackages-local ... %build ant test %install %mvn_artifact pom.xml lib/%{name}.jar %mvn_install -J api/ %files -f .mfiles %files javadoc -f .mfiles-javadoc</code></pre> </div> </div> <div class="ulist"> <div class="title">Details</div> <ul> <li> <p><code>%build</code> section uses <code>ant</code> command to build the project and run the tests. The used target(s) may vary depending on the <code>build.xml</code> file. You can use <code>ant -p</code> command to list the project info or manually look for <code><target></code> nodes in the <code>build.xml</code> file.</p> </li> <li> <p><code>%mvn_artifact</code> macro is used to request installation of an artifact that was not built using Maven. It expects a POM file and a JAR file. For POM only artifacts, the JAR part is omitted. See <a href="#_installing_additional_artifacts">Installing additional artifacts</a> for more information.</p> </li> <li> <p><code>%mvn_install</code> performs the actual installation. Optional <code>-J</code> parameter requests installation of generated Javadoc from given directory.</p> </li> <li> <p>This method of artifact installation allows using other XMvn macros such as <code>%mvn_alias</code> or <code>%mvn_package</code>.</p> </li> <li> <p><code>%mvn_install</code> generates <code>.mfiles</code> file which should be used to populate <code>%files</code> section with <code>-f</code> switch. For each subpackage there would be separate generated file named <code>.mfiles-subpackage-name</code>.</p> </li> <li> <p>All packages are required to own directories which they create (and which are not owned by other packages). JAR files are by default installed into subdirectory of <code>%{_javadir}</code>. To override this behavior, use <code>%mvn_file</code>.</p> </li> </ul> </div> <div class="sect2"> <h3 id="_apache_ivy"><a class="anchor" href="#_apache_ivy"></a>6.1. Apache Ivy</h3> <div class="paragraph"> <p>Apache Ivy provides an automatic dependency management for Ant managed builds. It uses Maven repositories for retrieving artifacts and supports many declarative features of Maven such as handling transitive dependencies.</p> </div> <div class="paragraph"> <p>XMvn supports local resolution of Ivy artifacts, their installation and requires generation.</p> </div> <div class="listingblock"> <div class="title">Spec file</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">BuildRequires: ivy-local ... %build ant -Divy.mode=local test %install %mvn_artifact ivy.xml lib/sample.jar %mvn_install -J api/ %files -f .mfiles %files -javadoc -f .mfiles-javadoc</code></pre> </div> </div> <div class="ulist"> <div class="title">Details</div> <ul> <li> <p><code>-Divy.mode=local</code> tells Ivy to use XMvn local artifact resolution instead of downloading from the Internet.</p> </li> <li> <p>If there is an <code>ivy-settings.xml</code> or similar file, which specifies remote repositories, it needs to be disabled, otherwise it would override local resolution.</p> </li> <li> <p><code>%mvn_artifact</code> supports installing artifacts described by Ivy configuration files.</p> </li> <li> <p><code>%mvn_install</code> performs the actual installation. Optional <code>-J</code> parameter requests installation of generated Javadoc from given directory.</p> </li> </ul> </div> <div class="paragraph"> <div class="title">Ivy files manipulation</div> <p>A subset of macros used to modify Maven POMs also work with <code>ivy.xml</code> files allowing the maintainer to add / remove / change dependencies without the need of making patches and rebasing them with each change. You can use dependency handling macros <code>%pom_add_dep</code>, <code>%pom_remove_dep</code>, <code>%pom_change_dep</code> and generic <code>%pom_xpath_*</code> macros. For more details, see corresponding manpages.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># Remove dependency on artifact with org="com.example" and # name="java-project" from ivy.xml file in current directory %pom_remove_dep com.example:java-project # Add dependency on artifact with org="com.example" and # name="foobar" to ./submodule/ivy.xml %pom_add_dep com.example:foobar submodule</code></pre> </div> </div> <div class="paragraph"> <div class="title">Using the <code>ivy:publish</code> task</div> <p>Ivy supports publishing built artifact with <code>ivy:publish</code> task. If your <code>build.xml</code> file already contains a task that calls <code>ivy:publish</code>, you can set the resolver attribute of the <code>ivy:publish</code> element to <code>xmvn</code>. This can be done with simple <code>%pom_xpath_set</code> call. Then when the task is run, XMvn can pick the published artifacts and install them during the run of <code>%mvn_install</code> without needing you to manually specify them with <code>%mvn_artifact</code>.</p> </div> <div class="listingblock"> <div class="title">Spec file using the <code>ivy:publish</code> task</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">BuildRequires: ivy-local ... %prep %pom_xpath_set ivy:publish/@resolver xmvn build.xml %build ant -Divy.mode=local test publish-local %install %mvn_install -J api/ %files -f .mfiles %files -javadoc -f .mfiles-javadoc</code></pre> </div> </div> <div class="ulist"> <div class="title">Details</div> <ul> <li> <p>The publish target may be named differently. Search the <code>build.xml</code> for occurences of <code>ivy:publish</code>.</p> </li> <li> <p><code>%mvn_install</code> will install all the published artifacts.</p> </li> </ul> </div> </div> </div> </div> <div class="sect1"> <h2 id="_maven"><a class="anchor" href="#_maven"></a>7. Maven</h2> <div class="sectionbody"> <div class="quoteblock"> <blockquote> <div class="paragraph"> <p>Apache Maven is a software project management and comprehension tool. Based on the concept of a project object model (POM), Maven can manage a project’s build, reporting and documentation from a central piece of information.</p> </div> </blockquote> <div class="attribution"> — https://maven.apache.org </div> </div> <div class="paragraph"> <p>Maven is by far the most consistent Java build system, allowing large amount of automation. In most common situations only following steps are necessary:</p> </div> <div class="olist arabic"> <ol class="arabic"> <li> <p>In <code>%build</code> section of the spec file use <code>%mvn_build</code> macro.</p> </li> <li> <p>In <code>%install</code> section, use <code>%mvn_install</code> macro.</p> </li> <li> <p>Use generated file <code>.mfiles</code> lists to populate <code>%files</code> section with <code>-f</code> switch.</p> </li> </ol> </div> <div class="listingblock"> <div class="title">Common spec file sections</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">BuildRequires: maven-local ... %build %mvn_build ... %install %mvn_install ... %files -f .mfiles %dir %{_javadir}/%{name} %files javadoc -f .mfiles-javadoc</code></pre> </div> </div> <div class="paragraph"> <p>The macros <code>%mvn_build</code> and <code>%mvn_install</code> automatically handle building of the JAR files and their subsequent installation to the correct directory. The corresponding POM and metadata files are also installed.</p> </div> <div class="sect2"> <h3 id="_packaging_maven_project"><a class="anchor" href="#_packaging_maven_project"></a>7.1. Packaging Maven project</h3> <div class="paragraph"> <p>This step by step guide will show you how to package Maven project. Let’s start with probably the simplest spec file possible.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">Unresolved directive in packaging_maven_project.adoc - include::{EXAMPLE}maven_project/simplemaven.spec[]</code></pre> </div> </div> <div class="paragraph"> <p>The spec file above is a real world example how it may look like for simple Maven project. Both <code>%build</code> and <code>%install</code> sections consist only of one line.</p> </div> <div class="paragraph"> <p>Another interesting line:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">10: BuildRequires: maven-local</code></pre> </div> </div> <div class="paragraph"> <p>All Maven projects need to have <code>BuildRequires</code> on <code>maven-local</code>. They also need to have <code>Requires</code> and <code>BuildRequires</code> on <code>jpackages-utils</code>, but build system adds these automatically. The package maintainer does not need to list them explicitly.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">31: %dir %{_javadir}/%{name}</code></pre> </div> </div> <div class="paragraph"> <p>By default, resulting JAR files will be installed in <code>%{_javadir}/%{name}</code>, therefore the package needs to own this directory.</p> </div> <div class="paragraph"> <p>The build could fail from many reasons, but one probably most common is build failure due to <a href="#_missing_dependency">missing dependencies</a>.</p> </div> <div class="paragraph"> <p>We can try to remove these missing dependencies from pom.xml and make Maven stop complaining about them. However, these removed dependencies may be crucial for building of the project and therefore it may be needed to package them later. Let’s remove the dependencies from <code>pom.xml</code>.</p> </div> <div class="listingblock"> <div class="title">Remove dependencies from pom.xml</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">... %prep %setup -q # Add following lines to %prep section of a spec file %pom_remove_dep :commons-io %pom_remove_dep :junit</code></pre> </div> </div> <div class="paragraph"> <p>The package maintainer can use a wide variety of “pom_” macros for modifying <code>pom.xml</code> files. See the <a href="#_macros_for_pom_modification">Macros for POM modification</a> section for more information.</p> </div> <div class="paragraph"> <p>Now try to build the project again. The build will fail with a <a href="#_compilation_failure">compilation failure</a>.</p> </div> <div class="paragraph"> <p>Oops, another problem. This time Maven thought it had all the necessary dependencies, but Java compiler found otherwise.</p> </div> <div class="paragraph"> <p>Now it is possible to either patch the source code not to depend on missing libraries or to package them. The second approach is usually correct. It is not necessary to package every dependency right away. The maintainer could package compile time dependencies first and keep the rest for later (test dependencies, etc.). But Maven needs to know that it should not try to run tests now. This can be achieved by passing <code>-f</code> option to <code>%mvn_build</code> macro. Maven will stop complaining about missing test scoped dependencies from now on.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p>Another reason to disable the test phase is to speed up the local build process. This can also be achieved by specifying an additional switch <code>--without=tests</code> to the <code>fedpkg</code> or the <code>mock</code> tool instead of adding a switch to <code>%mvn_build</code>.</p> </div> <div class="paragraph"> <p>Another switch <code>--without=javadoc</code> causes the build to skip Javadoc generation.</p> </div> </td> </tr> </table> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>It is always recommended to run all available test suites during build. It greatly improves quality of the package.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>We already have package which provides <code>commons-io:commons-io</code> artifact, let’s add it to the <code>BuildRequires</code>. Also disable tests for now.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">BuildRequires: maven-local BuildRequires: apache-commons-io ... %prep %setup -q # Comment out following lines in %prep section #%%pom_remove_dep :commons-io #%%pom_remove_dep :junit %build # Skip tests for now, missing dependency junit:junit:4.11 %mvn_build -f</code></pre> </div> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p>One can easily search for package which provides the desired artifact. Try <code>dnf repoquery --whatprovides 'mvn(commons-io:commons-io)'</code>, or see how to <a href="#_querying_repositories">query repositories</a>.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Now try to build the project one more time. The build should succeed now. Congrats, you managed to create an RPM from Maven project!</p> </div> <div class="paragraph"> <p>There is plenty of other things maintainer may want to do. For example, they may want to provide symbolic links to the JAR file in <code>%{_javadir}</code>.</p> </div> <div class="paragraph"> <p>This can be easily achieved with <code>%mvn_file</code> macro:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">%prep %setup -q %mvn_file : %{name}/%{name} %{name}</code></pre> </div> </div> <div class="paragraph"> <p>See <a href="#_alternative_jar_file_names">Alternative JAR File Names</a> section for more information.</p> </div> <div class="paragraph"> <p>Another quite common thing to do is adding aliases to Maven artifact. Try to run <code>rpm -qp --provides</code> on your locally built RPM package:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ rpm -qp --provides simplemaven-1.0-1.fc21.noarch.rpm mvn(com.example:simplemaven) = 1.0 simplemaven = 1.0-1.fc21</code></pre> </div> </div> <div class="paragraph"> <p>The output above tells us that the RPM package provides Maven artifact <code>com.example:simplemaven:1.0</code>. Upstream may change the <code>groupId:artifactId</code> with any new release. And it happens. For example <code>org.apache.commons:commons-io</code> changed to <code>commons-io:commons-io</code> some time ago. It is not a big deal for package itself, but it is a huge problem for other packages that depends on that particular package. Some packages may still have dependencies on old <code>groupId:artifactId</code>, which is suddenly unavailable. Luckily, there is an easy way how to solve the problems like these. Package maintainer can add aliases to actually provided Maven artifact.</p> </div> <div class="listingblock"> <div class="title">Add alias to Maven artifact</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">%mvn_alias org.example:simplemaven simplemaven:simplemaven</code></pre> </div> </div> <div class="paragraph"> <p>See <a href="#_additional_mappings">Additional Mappings</a> for more information on <code>%mvn_alias</code>.</p> </div> <div class="paragraph"> <p>Rebuild the pacakge and check <code>rpm -qp --provides</code> output again:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-shell hljs" data-lang="shell">$ rpm -qp --provides simplemaven-1.0-2.fc21.noarch.rpm mvn(com.example:simplemaven) = 1.0 mvn(simplemaven:simplemaven) = 1.0 simplemaven = 1.0-2.fc21</code></pre> </div> </div> <div class="paragraph"> <p>Now it does not matter if some other package depends on either of these listed artifact. Both dependencies will always be satisfied with your package.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="paragraph"> <p>One could try to fix dependencies in all the dependent packages instead of adding an alias to single package. It is almost always wrong thing to do.</p> </div> </td> </tr> </table> </div> </div> <div class="sect2"> <h3 id="_macros_for_maven_build_configuration"><a class="anchor" href="#_macros_for_maven_build_configuration"></a>7.2. Macros for Maven build configuration</h3> <div class="paragraph"> <p>Maven builds can be configured to produce alternative layout, include additional aliases in package metadata or create separate subpackages for certain artifacts.</p> </div> <div class="sect3"> <h4 id="_installing_additional_artifacts"><a class="anchor" href="#_installing_additional_artifacts"></a>7.2.1. Installing additional artifacts</h4> <div class="paragraph"> <p>It is possible to explicitly request an installation of any Maven artifact (JAR / POM file). Macro <code>%mvn_install</code> only knows about Maven artifacts that were created during execution of <code>%mvn_build</code>. Normally, any other artifacts which were built by some other method would need to be installed manually. <code>%mvn_build</code> macro does not even need to be used at all. Luckily, all artifacts created outside of <code>%mvn_build</code> can be marked for installation with <code>%mvn_artifact</code> macro. This macro creates configuration for <code>%mvn_install</code>.</p> </div> <div class="listingblock"> <div class="title">Requesting installation of Maven artifact</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">%prep ... # Request installation of POM and JAR file %mvn_artifact subpackage/pom.xml target/artifact.jar # Request installation of POM artifact (no JAR file) %mvn_artifact pom.xml # Request installation for JAR file specified by artifact coordinates %mvn_artifact webapp:webapp:war:3.1 webapp.war</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_additional_mappings"><a class="anchor" href="#_additional_mappings"></a>7.2.2. Additional Mappings</h4> <div class="paragraph"> <p>The macro <code>%mvn_alias</code> can be used to add additional mappings for given POM / JAR file. For example, if the POM file indicates that it contains <code>groupId</code> <code>commons-lang</code>, <code>artifactId</code> <code>commons-lang</code>, this macro ensures that we also add a mapping between <code>groupId</code> <code>org.apache.commons</code> and the installed JAR / POM files. This is necessary in cases where the groupId or artifactId may have changed, and other packages might require different IDs than those reflected in the installed POM.</p> </div> <div class="listingblock"> <div class="title">Adding more mappings for JAR/POM files example</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">%prep ... %mvn_alias "commons-lang:commons-lang" "org.apache.commons:commons-lang"</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_alternative_jar_file_names"><a class="anchor" href="#_alternative_jar_file_names"></a>7.2.3. Alternative JAR File Names</h4> <div class="paragraph"> <p>In some cases, it may be important to be able to provide symbolic links to actual JAR files. This can be achieved with <code>%mvn_file</code> macro. This macro allows packager to specify names of the JAR files, their location in <code>%{_javadir}</code> directory and also can create symbolic links to the JAR files. These links can be possibly located outside of the <code>%{_javadir}</code> directory.</p> </div> <div class="listingblock"> <div class="title">Adding file symlinks to compatibility</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">%prep ... %mvn_file :guice google/guice guice</code></pre> </div> </div> <div class="paragraph"> <p>This means that JAR file for artifact with ID "guice" (and any <code>groupId</code>) will be installed in <code>%{_javadir}/google/guice.jar</code> and there also will be a symbolic links to this JAR file located in <code>%{_javadir}/guice.jar</code>. Note the macro will add <code>.jar</code> extensions automatically.</p> </div> </div> <div class="sect3"> <h4 id="_single_artifact_per_package"><a class="anchor" href="#_single_artifact_per_package"></a>7.2.4. Single Artifact Per Package</h4> <div class="paragraph"> <p>If the project consists of multiple artifacts, it is recommended to install each artifact to the separate subpackage. The macro <code>%mvn_build -s</code> will generate separate <code>.mfiles</code> file for every artifact in the project. This file contains list of files related to specific artifact (typically JAR file, POM file and metadata). It can be later used in <code>%files</code> section of the spec file.</p> </div> <div class="listingblock"> <div class="title">Creating one subpackage for each generated artifact</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">... %description The Maven Plugin Tools contains... %package -n maven-plugin-annotations Summary: Maven Plugin Java 5 Annotations %description -n maven-plugin-annotations This package contains Java 5 annotations to use in Mojos. %package -n maven-plugin-plugin Summary: Maven Plugin Plugin %description -n maven-plugin-plugin The Plugin Plugin is used to... ... %build %mvn_build -s %install %mvn_install %files -f .mfiles-maven-plugin-tools %doc LICENSE NOTICE %files -n maven-plugin-annotations -f .mfiles-maven-plugin-annotations %files -n maven-plugin-plugin -f .mfiles-maven-plugin-plugin %files -f .mfiles-javadoc ...</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_assignment_of_the_maven_artifacts_to_the_subpackages"><a class="anchor" href="#_assignment_of_the_maven_artifacts_to_the_subpackages"></a>7.2.5. Assignment of the Maven Artifacts to the Subpackages</h4> <div class="paragraph"> <p>The macro <code>%mvn_package</code> allows maintainer to specify in which exact package the selected artifact will end up. It is something between singleton packaging, when each artifact has its own subpackage and default packaging, when all artifacts end up in the same package.</p> </div> <div class="listingblock"> <div class="title">Assigning multiple artifacts to single subpackage</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">... %prep %mvn_package ":plexus-compiler-jikes" plexus-compiler-extras %mvn_package ":plexus-compiler-eclipse" plexus-compiler-extras %mvn_package ":plexus-compiler-csharp" plexus-compiler-extras %build %mvn_build %install %mvn_install %files -f .mfiles %files -f .mfiles-plexus-compiler-extras %files -f .mfiles-javadoc</code></pre> </div> </div> <div class="paragraph"> <p>In above example, the artifacts <code>plexus-compiler-jikes</code>, <code>plexus-compiler-eclipse</code>, <code>plexus-compiler-csharp</code> will end up in package named <code>plexus-compiler-extras</code>. If there are some other artifacts beside these three mentioned (e.g. some parent POMs), then these will all end up in package named <code>%{name}</code>.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p><code>%mvn_package</code> macro supports wildcards and brace expansions, so whole <code>%prep</code> section from previous example can be replaced with single line: <code>%mvn_package ":plexus-compiler-{jikes,eclipse,csharp}" plexus-compiler-extras</code>.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>It is possible to assign artifacts into a package called <code>__noinstall</code>. This package name has a special meaning. And as you can guess, artifacts assigned into this package will not be installed anywhere and the package itself will not be created.</p> </div> <div class="listingblock"> <div class="title">Skipping installation of an artifact</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">%prep ... %mvn_package groupId:artifactId __noinstall</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_modifying_xmvn_configuration_from_within_spec_file"><a class="anchor" href="#_modifying_xmvn_configuration_from_within_spec_file"></a>7.2.6. Modifying XMvn configuration from within spec file</h4> <div class="paragraph"> <p>Some packages might need to modify XMvn’s configuration in order to build successfully or from other reasons. This can be achieved with <code>mvn_config</code> macro. For example, some old package can use <code>enum</code> as an identifier, but it is also keyword since Java 1.5. Such package will probably fail to build on current systems. This problem can be easily solved by passing <code>-source 1.4</code> to the compiler, so one could add following line to the spec file:</p> </div> <div class="listingblock"> <div class="title">Overriding default XMvn configuration</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">%prep ... %mvn_config buildSettings/compilerSource 1.4</code></pre> </div> </div> <div class="paragraph"> <p>XMvn’s configuration is quite complex, but well documented at the project’s <a href="https://mizdebsk.fedorapeople.org/xmvn/site/">official website</a>. The website should always be used as a primary source of information about XMvn configuration.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p>Read about XMvn’s configuration <a href="https://mizdebsk.fedorapeople.org/xmvn/site/configuration.html">basics</a> and see the full <a href="https://mizdebsk.fedorapeople.org/xmvn/site/config.html">configuration reference</a>.</p> </div> </td> </tr> </table> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p>All <code>%mvn_</code> macros have their own manual page which contains details on how to use them. All possible options should be documented there. These manual pages should be considered most up to date documentation right after source code. Try for example <code>man mvn_file</code>. These pages are also included in the <a href="#_manpages">Appendix</a>.</p> </div> </td> </tr> </table> </div> </div> </div> <div class="sect2"> <h3 id="_macros_for_pom_modification"><a class="anchor" href="#_macros_for_pom_modification"></a>7.3. Macros for POM modification</h3> <div class="paragraph"> <p>Sometimes Maven <code>pom.xml</code> files need to be patched before they are used to build packages. One could use traditional patches to maintain changes, but package maintainers should use <code>%pom_*</code> macros developed specially to ease this task. Using <code>%pom_*</code> macros not only increases readability of the spec file, but also improves maintainability of the package as there are no patches that would need to be rebased with each upstream release.</p> </div> <div class="paragraph"> <p>There are two categories of macros:</p> </div> <div class="ulist"> <ul> <li> <p>POM-specific macros - used to manipulate dependencies, modules, etc. Some of them also work on <code>ivy.xml</code> files.</p> </li> <li> <p>Generic XML manipulation macros - used to add / remove / replace XML nodes.</p> </li> </ul> </div> <div class="paragraph"> <p>The macros are designed to be called from <code>%prep</code> section of spec files. All the macros also have their own manual page. This document provides an overview of how they are used. For the technical details, refer to their respective <a href="#_manpages">manpages</a>.</p> </div> <div class="paragraph"> <div class="title">File specfication</div> <p>By default, a macro acts on a <code>pom.xml</code> file (or <code>ivy.xml</code> file) in the current directory. Different path can be explicitly specified via an argument (the last one, unless stated otherwise). Multiple paths can be specified as multiple arguments. If a path is a directory, it looks for a <code>pom.xml</code> file in that directory. For example:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># The following works on pom.xml file in the current directory %pom_remove_parent # The following works on submodule/pom.xml %pom_remove_parent submodule # The following works on submodule/pom.xml as well %pom_remove_parent submodule/pom.xml # The following works on submodule2/pom.xml and submodule2/pom.xml %pom_remove_parent submodule1 submodule2</code></pre> </div> </div> <div class="paragraph"> <div class="title">Recursive mode</div> <p>Most macros also support <strong>recursive</strong> mode, where the change is applied to the <code>pom.xml</code> and all its modules recursively. This can be used, for example, to remove a dependency from the whole project. It is activated by <code>-r</code> switch.</p> </div> <div class="sect3"> <h4 id="_dependency_manipulation_macros"><a class="anchor" href="#_dependency_manipulation_macros"></a>7.3.1. Dependency manipulation macros</h4> <div class="paragraph"> <div class="title">Removing dependencies</div> <p>Often dependencies specified in Maven <code>pom.xml</code> files need to be removed because of different reasons. <code>%pom_remove_dep</code> macro can be used to ease this task:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># Removes dependency with groupId "foo" and artifactId "bar" from pom.xml %pom_remove_dep foo:bar # Removes dependency on all artifacts with groupId "foo" from pom.xml %pom_remove_dep foo: # Removes dependency on all artifacts with artifactId "bar" from pom.xml %pom_remove_dep :bar # Removes dependency on all artifacts with artifactId "bar" from submodule1/pom.xml %pom_remove_dep :bar submodule1 # Removes dependency on all artifacts with artifactId "bar" from pom.xml # and all its submodules %pom_remove_dep -r :bar # Removes all dependencies from pom.xml %pom_remove_dep :</code></pre> </div> </div> <div class="paragraph"> <div class="title">Adding dependencies</div> <p>Dependencies can also be added to <code>pom.xml</code> with <code>%pom_add_dep</code> macro. Usage is very similar to <code>%pom_remove_dep</code>, see <code>$ man pom_add_dep</code> for more information.</p> </div> <div class="paragraph"> <div class="title">Changing dependencies</div> <p>Sometimes the artifact coordinates used in upstream <code>pom.xml</code> do not correspond to ones used in Fedora and you need to modify them. <code>%pom_change_dep</code> macro will modify all dependencies matching the first argument to artifact coordinates specified by the second argument. Note this macro also works in recursive mode.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># For all artifacts in pom.xml that have groupId 'example' change it to # 'com.example' while leaving artifactId and other parts intact %pom_change_dep example: com.example:</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_adding_removing_plugins"><a class="anchor" href="#_adding_removing_plugins"></a>7.3.2. Adding / removing plugins</h4> <div class="paragraph"> <p><code>%pom_remove_plugin</code> macro works exactly as <code>%pom_remove_dep</code>, except it removes Maven plugin invocations. Some examples:</p> </div> <div class="listingblock"> <div class="title">Removing Maven plugins from pom.xml files</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># Disables maven-jar-plugin so that classpath isn't included in manifests %pom_remove_plugin :maven-jar-plugin # Disable a proprietary plugin that isn't packaged for Fedora %pom_remove_plugin com.example.mammon:useless-proprietary-plugin submodule</code></pre> </div> </div> <div class="paragraph"> <p>Like in previous case, there is also a macro for adding plugins to <code>pom.xml</code>. See its <a href="#_pom_add_plugin">manual page</a> for more information.</p> </div> </div> <div class="sect3"> <h4 id="_disabling_unneeded_modules"><a class="anchor" href="#_disabling_unneeded_modules"></a>7.3.3. Disabling unneeded modules</h4> <div class="paragraph"> <p>Sometimes some submodules of upstream project cannot be built for various reasons and there is a need to disable them. This can be achieved by using <code>%pom_disable_module</code>, for example:</p> </div> <div class="listingblock"> <div class="title">Disabling specific project modules</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># Disables child-module-1, a submodule of the main pom.xml file %pom_disable_module child-module-1 # Disables grandchild-module, a submodule of child-module-2/pom.xml %pom_disable_module grandchild-module child-module-2</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_working_with_parent_pom_references"><a class="anchor" href="#_working_with_parent_pom_references"></a>7.3.4. Working with parent POM references</h4> <div class="paragraph"> <p>Macro <code>%pom_remove_parent</code> removes reference to a parent POM from Maven POM files. This can be useful when parent POM is not yet packaged (e.g. because of licensing issues) and at the same time it is not really needed for building of the project. There are also macros for adding parent POM reference (<code>%pom_add_parent</code>) and replacing existing reference with new one (<code>%pom_set_parent</code>).</p> </div> <div class="listingblock"> <div class="title">Manipulating parent POM references</div> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># Remove reference to a parent POM from ./pom.xml %pom_remove_parent # Remove reference to a parent POM from ./submodule/pom.xml %pom_remove_parent submodule # Add parent POM reference to ./pom.xml %pom_add_parent groupId:artifactId # Replace existing parent POM reference in ./pom.xml %pom_set_parent groupId:artifactId:version</code></pre> </div> </div> </div> <div class="sect3"> <h4 id="_macros_for_performing_generic_modifications"><a class="anchor" href="#_macros_for_performing_generic_modifications"></a>7.3.5. Macros for performing generic modifications</h4> <div class="paragraph"> <p>The above macros cover the most common cases of modifying <code>pom.xml</code> files, however if there is a need to apply some less-common patches there are also three generic macros for modifying <code>pom.xml</code> files. These generic macros can also be applied to other XML files, such as Ant’s <code>build.xml</code> files.</p> </div> <div class="paragraph"> <p>They all take a <a href="https://www.w3.org/TR/xpath/">XPath</a> 1.0 expression that selects XML nodes to be acted on (removed, replaced, etc.).</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <i class="fa icon-note" title="Note"></i> </td> <td class="content"> <div class="title">Handling XML namespaces</div> <div class="paragraph"> <p>POM files use a specific namespace - <code>http://maven.apache.org/POM/4.0.0</code>. The easiest way to respect this namespace in XPath expressions is prefixing all node names with <code>pom:</code>. For example, <code>pom:environment/pom:os</code> will work because it selects nodes from <code>pom</code> namespace, but <code>environment/os</code> won’t find anything because it looks for nodes that do not belong to any XML namespace. It is needed even if the original POM file didn’t contain proper POM namespace, since it will be added automatically. Note that this requirement is due to limitation of XPath 1.0 and we cannot work it around.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <div class="title">Removing nodes</div> <p><code>%pom_xpath_remove</code> can be used to remove arbitrary XML nodes.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># Removes extensions from the build %pom_xpath_remove "pom:build/pom:extensions" module/pom.xml</code></pre> </div> </div> <div class="paragraph"> <div class="title">Injecting nodes</div> <p><code>%pom_xpath_inject</code> macro is capable of injecting arbitrary XML code to any <code>pom.xml</code> file. The injected code is the last argument - optional file paths go before it (unlike most other macros). To pass a multiline snippet, quote the argument as in the following example.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># Add additional exclusion into maven-wagon dependency %pom_xpath_inject "pom:dependency[pom:artifactId='maven-wagon']/pom:exclusions" " <exclusion> <groupId>antlr</groupId> <artifactId>antlr</artifactId> </exclusion>" # The same thing, but with explicit file path %pom_xpath_inject "pom:dependency[pom:artifactId='maven-wagon']/pom:exclusions" pom.xml " <exclusion> <groupId>antlr</groupId> <artifactId>antlr</artifactId> </exclusion>"</code></pre> </div> </div> <div class="paragraph"> <div class="title">Changing nodes' content</div> <p><code>%pom_xpath_set</code> replaces content of the arbitrary XML nodes with specified value (can contain XML nodes).</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># Change groupId of a parent %pom_xpath_set "pom:parent/pom:groupId" "org.apache"</code></pre> </div> </div> <div class="paragraph"> <div class="title">Replacing nodes</div> <p><code>%pom_xpath_replace</code> replaces a XML node with specified XML code.</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># Change groupId of a parent (note the difference from %pom_xpath_set) %pom_xpath_replace "pom:parent/pom:groupId" "<groupId>org.apache</groupId>"</code></pre> </div> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_common_errors"><a class="anchor" href="#_common_errors"></a>8. Common Errors</h2> <div class="sectionbody"> <div class="paragraph"> <p>This section contains explanations and solutions/workarounds for common errors which can be encountered during packaging.</p> </div> <div class="sect2"> <h3 id="_missing_dependency"><a class="anchor" href="#_missing_dependency"></a>8.1. Missing dependency</h3> <div class="listingblock"> <div class="content"> <pre>[ERROR] Failed to execute goal on project simplemaven: Could not resolve dependencies for project com.example:simplemaven:jar:1.0: The following artifacts could not be resolved: commons-io:commons-io:jar:2.4, junit:junit:jar:4.11: Cannot access central (http://repo.maven.apache.org/maven2) in offline mode and the artifact commons-io:commons-io:jar:2.4 has not been downloaded from it before. -> [Help 1]</pre> </div> </div> <div class="paragraph"> <p>Maven wasn’t able to build project <code>com.example:simplemaven</code> because it couldn’t find some dependencies (in this case <code>commons-io:commons-io:jar:2.4</code> and <code>junit:junit:jar:4.11</code>)</p> </div> <div class="paragraph"> <p>You have multiple options here:</p> </div> <div class="ulist"> <ul> <li> <p>If you suspect that a dependency is not necessary, you can remove it from <code>pom.xml</code> file and Maven will stop complaining about it. You can use wide variety of <a href="#_macros_for_pom_modification">macros</a> for modifying POM files. The one for removing dependencies is called <a href="#_dependency_manipulation_macros"><code>%pom_remove_dep</code></a>.</p> </li> <li> <p>There is a mock plugin that can automate installation of missing dependencies. When you’re using mock, pass additional <code>--enable-plugin pm_request</code> argument and the build process would be able to install missing dependencies by itself. You still need to add the <code>BuildRequires</code> later, because you need to build the package in Koji, where the plugin is not allowed. You should do so using <code>xmvn-builddep build.log</code>, where <code>build.log</code> is the path to mock’s build log. It will print a list of <code>BuildRequires</code> lines, which you can directly paste into the specfile. To verify that the <code>BuildRequires</code> you just added are correct, you can rebuild the package once more without the plugin enabled.</p> </li> <li> <p>Add the artifacts to <code>BuildRequires</code> manually. Maven packages have virtual provides in a format <code>mvn(artifact coordinates)</code>, where artifact coordinates are in the format which Maven used in the error message, but without version for non-compat packages (most of the packages you encounter). Virtual provides can be used directly in <code>BuildRequires</code>, so in this case it would be:</p> </li> </ul> </div> <div class="listingblock"> <div class="content"> <pre>BuildRequires: mvn(commons-io:commons-io) BuildRequires: mvn(junit:junit)</pre> </div> </div> </div> <div class="sect2"> <h3 id="_compilation_failure"><a class="anchor" href="#_compilation_failure"></a>8.2. Compilation failure</h3> <div class="listingblock"> <div class="content"> <pre>[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project simplemaven: Compilation failure: Compilation failure: [ERROR] /builddir/build/BUILD/simplemaven-1.0/src/main/java/com/example/Main.java:[3,29] package org.apache.commons.io does not exist [ERROR] /builddir/build/BUILD/simplemaven-1.0/src/main/java/com/example/Main.java:[8,9] cannot find symbol [ERROR] symbol: class FileUtils [ERROR] location: class com.example.Main [ERROR] -> [Help 1]</pre> </div> </div> <div class="paragraph"> <p>Java compiler couldn’t find given class on classpath or incompatible version was present. This could be caused by following reasons:</p> </div> <div class="ulist"> <ul> <li> <p><code>pom.xml</code> requires different version of the Maven artifact than the local repository provides</p> </li> <li> <p><code>pom.xml</code> is missing a necessary dependency</p> </li> </ul> </div> <div class="paragraph"> <p>Different versions of same library may provide slightly different API. This means that project doesn’t have to be buildable if different version is provided. If the library in local repository is older than the one required by project, then the library could be updated. If the project requires older version, then the project should be ported to latest stable version of the library (this may require cooperation with project’s upstream). If none of these is possible from some reason, it is still possible to introduce new <code>compat</code> package. See <a href="#_compatibility_versions">compat packages</a> section for more information on this topic.</p> </div> <div class="paragraph"> <p>Sometimes <code>pom.xml</code> doesn’t list all the necessary dependencies, even if it should. Dependencies can also depend on some other and typically all these will be available to the project which is being built. The problem is that local repository may contain different versions of these dependencies. And even if these versions are fully compatible with the project, they may require slightly different set of dependencies. This could lead to build failure if <code>pom.xml</code> doesn’t specify all necessary dependencies and relies on transitive dependencies. Such a missing dependency may be considered a bug in the project. The solution is to explicitly add missing dependency to the <code>pom.xml</code>. This may be easily done by using <code>%pom_add_dep</code> macro. See the section about <a href="#_macros_for_pom_modification">macros for POM modification</a> for more information.</p> </div> </div> <div class="sect2"> <h3 id="_requires_cannot_be_generated"><a class="anchor" href="#_requires_cannot_be_generated"></a>8.3. Requires cannot be generated</h3> <div class="listingblock"> <div class="content"> <pre>Following dependencies were not resolved and requires cannot be generated. Either remove the dependency from pom.xml or add proper packages to BuildRequires: org.apache.maven.doxia:doxia-core::tests:UNKNOWN</pre> </div> </div> <div class="paragraph"> <p>Most often this error happens when one part of the package depends on an attached artifact which is not being installed. Automatic RPM requires generator then tries to generate requires on artifact which is not being installed. This would most likely result in a broken RPM package so generator halts the build.</p> </div> <div class="paragraph"> <p>There are usually two possible solutions for this problem:</p> </div> <div class="ulist"> <ul> <li> <p>Install attached artifact in question. For the above error following macro would install artifacts with <code>tests</code> classifiers into <code>tests</code> subpackage.</p> </li> </ul> </div> <div class="listingblock"> <div class="content"> <pre>%mvn_package :::tests: %{name}-tests</pre> </div> </div> <div class="ulist"> <ul> <li> <p>Remove dependency on problematic artifact. This can involve <code>pom.xml</code> modifications, disabling tests or even code changes so it is usually easier to install the dependency.</p> </li> </ul> </div> </div> <div class="sect2"> <h3 id="_dependencies_with_scope_system"><a class="anchor" href="#_dependencies_with_scope_system"></a>8.4. Dependencies with scope <code>system</code></h3> <div class="listingblock"> <div class="content"> <pre>[ERROR] Failed to execute goal org.fedoraproject.xmvn:xmvn-mojo:1.2.0:install (default-cli) on project pom: Some reactor artifacts have dependencies with scope "system". Such dependencies are not supported by XMvn installer. You should either remove any dependencies with scope "system" before the build or not run XMvn instaler. -> [Help 1]</pre> </div> </div> <div class="paragraph"> <p>Some Maven artifacts try to depend on exact system paths. Most usually this dependency is either on <code>com.sun:tools</code> or <code>sun.jdk:jconsole</code>. Dependencies with system scope cause issues with our tooling and requires generators so they are not supported.</p> </div> <div class="paragraph"> <p>Easiest way to solve this for above two dependencies is by removing and adding back the dependency without <code><scope></code> or <code><systemPath></code> nodes:</p> </div> <div class="listingblock"> <div class="content"> <pre>%pom_remove_dep com.sun:tools %pom_add_dep com.sun:tools</pre> </div> </div> </div> </div> </div> <div class="sect1"> <h2 id="_migration_from_older_tools"><a class="anchor" href="#_migration_from_older_tools"></a>9. Migration from older tools</h2> <div class="sectionbody"> <div class="paragraph"> <p>This section describes how to migrate packages that use older deprecated tools to current ones.</p> </div> <div class="sect2"> <h3 id="_add_maven_depmap_macro"><a class="anchor" href="#_add_maven_depmap_macro"></a>9.1. <code>%add_maven_depmap</code> macro</h3> <div class="paragraph"> <p><code>%add_maven_depmap</code> macro was used to manually install Maven artifacts that were built with Apache Ant or <code>mvn-rpmbuild</code>. It is now deprecated and its invocations should be replaced with <code>%mvn_artifact</code> and <code>%mvn_install</code>.</p> </div> <div class="paragraph"> <p>Artifact files, Maven POM files and their installation directories no longer need to be manually installed, since that is done during run of <code>%mvn_install</code>. The installed files also don’t need to be explicitly enumerated in <code>%files</code> section. Generated file <code>.mfiles</code> should be used instead.</p> </div> <div class="paragraph"> <p>Relevant parts of specfile using <code>%add_maven_depmap</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec">BuildRequires: javapackages-tools Requires: some-library ... %build ant test %install install -d -m 755 $RPM_BUILD_ROOT%{_javadir} install -m 644 target/%{name}.jar $RPM_BUILD_ROOT%{_javadir}/%{name}.jar install -d -m 755 $RPM_BUILD_ROOT%{_mavenpomdir} install -m 644 %{name}.pom $RPM_BUILD_ROOT/%{_mavenpomdir}/JPP-%{name}.pom # Note that the following call is equivalent to invoking the macro # without any parameters %add_maven_depmap JPP-%{name}.pom %{name}.jar # javadoc install -d -m 755 $RPM_BUILD_ROOT%{_javadocdir}/%{name} cp -pr api/* $RPM_BUILD_ROOT%{_javadocdir}/%{name} %files %{_javadir}/* %{_mavenpomdir}/* %{_mavendepmapfragdir}/* %files javadoc %doc %{_javadocdir}/%{name}</code></pre> </div> </div> <div class="paragraph"> <p>The same specfile migrated to <code>%mvn_artifact</code> and <code>%mvn_install</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlightjs highlight"><code class="language-spec hljs" data-lang="spec"># mvn_* macros are located in javapackages-local package BuildRequires: javapackages-local # Since XMvn generates requires automatically, it is no longer needed # nor recommended to specify manual Requires tags, unless the dependency # information in the POM is incomplete or you need to depend on non-java # packages ... %prep # The default location for installing JAR files is %{_javadir}/%{name}/ # Because our original specfile put the JAR directly to %{_javadir}, we # want to override this behavior. The folowing call tells XMvn to # install the groupId:artifactId artifact as %{_javadir}/%{name}.jar %mvn_file groupId:artifactId %{name} %build ant test # Tell XMvn which artifact belongs to which POM %mvn_artifact %{name}.pom target/%{name}.jar %install # It is not necessary to install directories and artifacts manually, # mvn_install will take care of it # Optionally use -J parameter to specify path to directory with built # javadoc %mvn_install -J api # Use autogenerated .mfiles file instead of specifying individual files %files -f .mfiles %files javadoc -f .mfiles-javadoc</code></pre> </div> </div> <div class="paragraph"> <div class="title">Aliases and subpackages</div> <p><code>%add_maven_depmap</code> had <code>-a</code> switch to specify artifact aliases and <code>-f</code> switch to support splitting artifacts across multiple subpackages. To achieve the same things with <code>%mvn_*</code> macros, see <a href="#_additional_mappings">Additional Mappings</a> and <a href="#_assignment_of_the_maven_artifacts_to_the_subpackages">Assignment of the Maven Artifacts to the Subpackages</a>.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <i class="fa icon-tip" title="Tip"></i> </td> <td class="content"> <div class="paragraph"> <p>If the project consists of multiple artifacts and parent POMs are among them, call <code>%mvn_artifact</code> on these parent POMs first.</p> </div> </td> </tr> </table> </div> <div class="paragraph"> <p>Unresolved directive in sections.adoc - include::{EXAMPLE}manpages.adoc[]</p> </div> </div> </div> </div> <div id="" class="mt-16"> <p class="contribute px-6 py-3 w-fit bg-gray-100 dark:bg-fp-blue-darker rounded-full">Want to help? <a class="" href="https://docs.fedoraproject.org/en-US/fedora-docs/contributing-docs/">Learn how to contribute to Fedora Docs <span class="ml-2 inline-block text-3xl leading-4 h-max align-top text-black dark:text-white">›</span></a></p> </div> </article> </div> </main> </div> <footer class="flex flex-col bg-fp-gray-lightest dark:bg-fp-blue-darkest dark:text-fp-gray-light text-sm dark:border-t dark:border-gray-800"> <section class="pt-2 pb-6 px-2"> <p class="text-center">All Fedora Documentation content available under <a href="http://creativecommons.org/licenses/by-sa/4.0/legalcode">CC BY-SA 4.0</a> or, when specifically noted, under another <a href="https://fedoraproject.org/wiki/Licensing:Main">accepted</a> free and open content license.</p> <div class="container mx-auto flex flex-col lg:flex-row my-4"> <div class="mx-auto lg:mx-0 lg:basis-3/12"> <img src="../_/img/fedora-blue.png" alt="Fedora Logo" class="w-36 mb-4 lg:mb-0" /> </div> <ul class="mx-4 flex items-center grow justify-center gap-4 lg:mx-0 lg:gap-12 xl:gap-20 2xl:gap-28 lg:justify-start" > <li class="list-none"> <a href="/en-US/legal/privacy/" class="text-fp-gray-darkest dark:text-fp-gray transition duration-300 ease-in-out hover:text-fp-gray dark:hover:text-fp-gray-light" >Privacy Statement</a > </li> <li class="list-none"> <a href="/en-US/legal/" class="text-fp-gray-darkest transition duration-300 ease-in-out hover:text-fp-gray dark:text-fp-gray dark:hover:text-fp-gray-light" >Legal</a > </li> <li class="list-none"> <a href="/en-US/project/code-of-conduct/" class="text-fp-gray-darkest transition duration-300 ease-in-out hover:text-fp-gray dark:text-fp-gray dark:hover:text-fp-gray-light" >Code of Conduct</a > </li> <li class="list-none"> <a href="https://getfedora.org/en/sponsors/" class="text-fp-gray-darkest transition duration-300 ease-in-out hover:text-fp-gray dark:text-fp-gray dark:hover:text-fp-gray-light" >Sponsors</a > </li> </ul> </div> <p class="text-center text-xs text-fp-gray-dark">Last build: 2025-02-21 14:50:11 UTC | Last content update: 2024-07-09 </p> </section> <!-- Red Hat Sponsorship Section --> <section class="bg-black py-6 text-center md:text-left px-2"> <div class="container mx-auto flex flex-col lg:flex-row"> <div class="mx-auto items-center lg:mx-0 lg:basis-3/12"> <img src="../_/img/logo-sponsored-by-red-hat.png" alt="Sponsored by Red Hat Logo" class="mb-4 xl:mb-0" /> </div> <div class="flex items-center justify-center text-center lg:text-left lg:ml-8 xl:-ml-8 2xl:ml-5"> <p class="text-white"> Fedora is sponsored by Red Hat. <a class="block text-fp-gray xl:ml-2 xl:inline" href="https://www.redhat.com/en/technologies/linux-platforms/articles/relationship-between-fedora-and-rhel"> Learn more about the relationship between Red Hat and Fedora. </a> </p> </div> </div> </section> </footer> <script id="site-script" src="../_/js/site.js" data-ui-root-path="../_"></script> <script async src="../_/js/vendor/highlight.js"></script> <script async src="../_/js/vendor/datatables.js"></script> <script async src="../_/js/vendor/tabs.js"></script> <script src="../_/js/vendor/lunr.js"></script> <script src="../_/js/search-ui.js" id="search-ui-script" data-site-root-path=".." data-snippet-length="100" data-stylesheet="../_/css/search.css"></script> <script async src="../search-index.js"></script> </body> </html>