CINXE.COM

GN in ChromeOS

<!DOCTYPE html> <head> <meta charset="utf-8"> <title>GN in ChromeOS</title> <link rel="stylesheet" href="/_stylesheets/@docsearch/style.css"> <link rel="stylesheet" href="/_stylesheets/default.css"> <link rel="stylesheet" href="/_stylesheets/highlight.js/github.min.css"> </head> <!-- Configure Google Analytics v4 --> <!-- Google tag (gtag.js) --> <script async src="https://www.googletagmanager.com/gtag/js?id=G-24XP4PG02H"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-24XP4PG02H'); </script> <header> <a href="/"> <img alt="the Chromium logo" src="/_assets/icon-chromium-96.png" width="48" height="48"> <h2>The Chromium Projects</h2> </a> <div id="search"></div> </header> <div id="main-wrapper"> <nav id="sidebar-left"> <section> <a href="/chromium-projects">Home</a> <a href="/Home">Chromium</a> <a href="/chromium-os">ChromiumOS</a> </section> <section> <h4>Quick links</h4> <a href="/for-testers/bug-reporting-guidelines">Report bugs</a> <a href="/developers/discussion-groups">Discuss</a> </section> <section> <h4>Other sites</h4> <a href="https://blog.chromium.org/">Chromium Blog</a> <a href="https://developer.chrome.com/extensions">Google Chrome Extensions</a> </section> <section id="license" role="complementary"> Except as otherwise <a href="https://developers.google.com/site-policies.html#restrictions">noted</a>, the content of this page is licensed under a <a href="https://creativecommons.org/licenses/by/2.5/">Creative Commons Attribution 2.5 license</a>, and examples are licensed under the <a href="https://chromium.googlesource.com/chromium/src/+/HEAD/LICENSE">BSD License</a>. </section> <section id="privacy" role="complementary"> <a href="https://policies.google.com/privacy">Privacy</a> </section> <a id="edit-this-page" href="https://edit.chromium.org/edit?repo=chromium/website/main&file=site/chromium-os/developer-library/reference/build/chromeos-gn/index.md&cloneRepo=chromium/website:refs/heads/main&fullPath=chromium/site/chromium-os/developer-library/reference/build/chromeos-gn/index.md">Edit this page</a> </nav> <main> <div class="breadcrumbs"> <a href="/chromium-os/developer-library/reference">ChromiumOS &gt; Reference</a> &gt; </div> <h1>GN in ChromeOS</h1> <p>New packages should use <a href="https://gn.googlesource.com/gn/+/HEAD/docs/reference.md">GN</a> as their build system.</p> <p>See the official <a href="https://gn.googlesource.com/gn/+/HEAD/docs/quick_start.md#Step_by_step">step-by-step introduction</a> for the GN basics. This article discusses ChromeOS specific stuff.</p> <nav class="table-of-contents"><ol><li><a href="#how-to-build-your-package-with-gn">How to build your package with GN</a></li><li><a href="#how-to-write-ebuilds">How to write ebuilds</a><ol><li><a href="#packages-outside-platform2">Packages outside platform2</a></li></ol></li><li><a href="#how-to-install-files">How to install files</a><ol><li><a href="#installing-targets-defined-in-buildgn">Installing Targets defined in BUILD.gn</a><ol><li><a href="#variable">Variable</a></li><li><a href="#installing-executable-targets">Installing executable targets</a></li><li><a href="#installing-shared-library-targets">Installing Shared Library Targets</a></li><li><a href="#installing-static-library-targets">Installing Static Library Targets</a></li></ol></li><li><a href="#installing-files-not-defined-in-buildgn">Installing files not defined in BUILD.gn</a><ol><li><a href="#variables">Variables</a></li><li><a href="#usage">Usage</a></li></ol></li></ol></li><li><a href="#how-to-check-use-flags-in-gn">How to check USE flags in GN</a></li><li><a href="#how-to-write-unit-tests">How to write unit tests</a><ol><li><a href="#declaring-tests-in-buildgn">Declaring tests in BUILD.gn</a></li></ol></li><li><a href="#faq">FAQ</a><ol><li><a href="#how-to-create-standalone-static-library">How to create standalone static library?</a></li></ol></li></ol></nav><h2 id="how-to-build-your-package-with-gn" tabindex="-1"><a class="header-anchor" href="#how-to-build-your-package-with-gn">How to build your package with GN</a></h2> <p>Example: <a href="https://chromium.googlesource.com/chromiumos/platform2/+/HEAD/arc/adbd/BUILD.gn">arc/adbd/BUILD.gn</a></p> <ul> <li>Put <code>BUILD.gn</code> in your package directory, which is determined by <code>PLATFORM_SUBDIR</code> in your ebuild. Existence of <code>BUILD.gn</code> indicates to the platform2 build system that GN should be used to build this package.</li> <li>Have a target named <code>&quot;all&quot;</code> in the <code>BUILD.gn</code>. It's the root target built by the platform2 build system. Typically it's a <code>group</code> target depends on all the targets to be built.</li> <li><code>common-mk/</code> contains common templates or common settings, which your build files can utilize. <ul> <li><code>pkg_config.gni</code> defines the <code>pkg_config</code> rule to generate configs for package dependencies.</li> <li><code>BUILDCONFIG.gn</code> defines the default configs for each target type (e.g. executable). You can remove default configs in individual target with <code>configs -=</code> if needed. (<a href="https://crrev.com/d2f92d07e9b0950157b7ce3a0f70cfee72fe76e7/hammerd/BUILD.gn#39">example</a>)</li> </ul> </li> </ul> <h2 id="how-to-write-ebuilds" tabindex="-1"><a class="header-anchor" href="#how-to-write-ebuilds">How to write ebuilds</a></h2> <p>Example: <a href="https://chromium.googlesource.com/chromiumos/overlays/chromiumos-overlay/+/HEAD/chromeos-base/arc-adbd/arc-adbd-9999.ebuild">arc-adbd-9999.ebuild</a></p> <p>Note we should add <code>.gn</code> in <code>CROS_WORKON_SUBTREE</code> so that the platform2 build system can access the file.</p> <h3 id="packages-outside-platform2" tabindex="-1"><a class="header-anchor" href="#packages-outside-platform2">Packages outside platform2</a></h3> <p>For packages outside platform2, use <code>CROS_WORKON_DESTDIR</code> to copy the package under <code>&lt;workspace&gt;/platform2/</code> while building it. (<a href="https://crrev.com/2bee6447043f11d39c61d2c3ea0b02287793dcf9/chromeos-base/update_engine/update_engine-9999.ebuild#8">example</a>)</p> <h2 id="how-to-install-files" tabindex="-1"><a class="header-anchor" href="#how-to-install-files">How to install files</a></h2> <h3 id="installing-targets-defined-in-buildgn" tabindex="-1"><a class="header-anchor" href="#installing-targets-defined-in-buildgn">Installing Targets defined in BUILD.gn</a></h3> <p>A file built by a GN target, either by <code>executable</code>, <code>shared_library</code> or <code>static_library</code>, can be installed by specifying <code>install_path</code>.</p> <p>A target that install the output must be a dependency of <code>group(&quot;all&quot;)</code>.</p> <h4 id="variable" tabindex="-1"><a class="header-anchor" href="#variable">Variable</a></h4> <ul> <li><code>install_path</code> <ul> <li>An install destination path.</li> </ul> </li> </ul> <h4 id="installing-executable-targets" tabindex="-1"><a class="header-anchor" href="#installing-executable-targets">Installing executable targets</a></h4> <ul> <li> <p><code>install_path</code> must end in <code>bin</code> or <code>sbin</code>.</p> </li> <li> <p>When you specify the <code>install_path</code> simply as <code>bin</code>, the binary will be installed into <code>/usr/bin</code>.</p> <pre><code class="language-gn">executable(&quot;executable_target&quot;) { sources = [ &quot;source.cc&quot; ] install_path = &quot;bin&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">dobin <span class="hljs-variable">${OUT}</span>/executable_target </code></pre> </li> <li> <p>If you want to change the destination, you can specify the absolute path.</p> <pre><code class="language-gn">executable(&quot;executable_target&quot;) { sources = [ &quot;source.cc&quot; ] install_path = &quot;/sbin&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">into / dosbin <span class="hljs-variable">${OUT}</span>/executable_target </code></pre> </li> </ul> <h4 id="installing-shared-library-targets" tabindex="-1"><a class="header-anchor" href="#installing-shared-library-targets">Installing Shared Library Targets</a></h4> <p>Installing shared library requires specifying <code>install_path</code> in the <code>shared_library</code> target.</p> <ul> <li> <p>The <code>install_path</code> must end in <code>lib</code>.</p> </li> <li> <p>When you specify the <code>install_path</code> simply as <code>lib</code>, the correct ABI-specific libdir (e.g. <code>/usr/lib</code> or <code>/usr/lib64</code>) will be used.</p> <pre><code class="language-gn">shared_library(&quot;libtarget&quot;) { sources = [ &quot;source.cc&quot; ] install_path = &quot;lib&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">dolib.so <span class="hljs-variable">${OUT}</span>/lib/libtarget </code></pre> </li> <li> <p>If you want to change the destination, you can specify the absolute path.</p> <pre><code class="language-gn">shared_library(&quot;libtarget&quot;) { sources = [ &quot;source.cc&quot; ] install_path = &quot;/usr/local/lib&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">into /usr/local dolib.so <span class="hljs-variable">${OUT}</span>/lib/libtarget </code></pre> </li> </ul> <h4 id="installing-static-library-targets" tabindex="-1"><a class="header-anchor" href="#installing-static-library-targets">Installing Static Library Targets</a></h4> <p>Installing static libraries requires specifying <code>install_path</code> in the <code>static_library</code> target.</p> <ul> <li> <p>The <code>install_path</code> must end in <code>lib</code>.</p> </li> <li> <p>When you specify the <code>install_path</code> simply as <code>lib</code>, it installs into <code>/usr/lib</code>.</p> <pre><code class="language-gn">static_library(&quot;libtarget&quot;) { sources = [ &quot;source.cc&quot; ] install_path = &quot;lib&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">dolib.a <span class="hljs-variable">${OUT}</span>/libtarget </code></pre> </li> <li> <p>If you want to change the destination, you can specify the absolute path.</p> <pre><code class="language-gn">static_library(&quot;libtarget&quot;) { sources = [ &quot;source.cc&quot; ] install_path = &quot;/usr/local/lib&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">into /usr/local dolib.a <span class="hljs-variable">${OUT}</span>/libtarget </code></pre> </li> </ul> <h3 id="installing-files-not-defined-in-buildgn" tabindex="-1"><a class="header-anchor" href="#installing-files-not-defined-in-buildgn">Installing files not defined in BUILD.gn</a></h3> <p>You can install files that are not generated by GN and ninja by using <code>install_config</code> target.</p> <h4 id="variables" tabindex="-1"><a class="header-anchor" href="#variables">Variables</a></h4> <ul> <li><code>sources</code> (required) <ul> <li>A list of files to be installed.</li> </ul> </li> <li><code>install_path</code> (optional) <ul> <li>An install destination path or an alias that maps to a corresponding destination path. <ul> <li>default: <code>/</code></li> <li><code>dbus_system_d</code> - <code>/etc/dbus-1/system.d</code></li> <li><code>dbus_system_services</code> - <code>/usr/share/dbus-1/system-services</code></li> <li><code>minijail_conf</code> - <code>/usr/share/minijail</code></li> <li><code>seccomp_policy</code> - <code>/usr/share/policy</code></li> <li><code>tmpfilesd</code> - <code>/usr/lib/tmpfiles.d</code></li> <li><code>tmpfiled_ondemand</code> - <code>/usr/lib/tmpfiles.d/on-demand</code></li> <li><code>upstart</code> - <code>/etc/init</code></li> </ul> </li> </ul> </li> <li><code>recursive</code> (optional) <ul> <li>A boolean, indicating whether to install files recursively.</li> <li>default: <code>false</code></li> </ul> </li> <li><code>options</code> (optional) <ul> <li>A string of options for installing files.</li> <li>default: <code>&quot;-m0644&quot;</code></li> </ul> </li> <li><code>outputs</code> (optional) <ul> <li>A list of new file names, if sources should be renamed too.</li> <li>When not specified, original names are used.</li> </ul> </li> <li><code>symlinks</code> (optional) <ul> <li>A list of symbolic links to be created.</li> <li>When install_path is specified, links are created in <code>${install_path}/${symlink}</code></li> </ul> </li> </ul> <h4 id="usage" tabindex="-1"><a class="header-anchor" href="#usage">Usage</a></h4> <ul> <li> <p>To install files, add <code>install_config</code> into dependency tree of <code>group(&quot;all&quot;)</code>.</p> <pre><code class="language-gn">install_config(&quot;install_init&quot;) { sources = [ &quot;init/initialize.conf&quot; ] install_path = &quot;upstart&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">insinto /etc/init doins init/initialize.conf </code></pre> </li> <li> <p>To install files recursively, set <code>recursive</code> to <code>true</code>.</p> <pre><code class="language-gn">install_config(&quot;install_rec&quot;) { sources = [ &quot;source_directory&quot; ] install_path = &quot;/usr/local&quot; recursive = true } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">insinto /usr/local doins -r source_directory </code></pre> </li> <li> <p>When you want to change owner or permission, specify <code>options</code>.</p> <pre><code class="language-gn">install_config(&quot;install_exe&quot;) { sources = [ &quot;source&quot; ] install_path = &quot;/usr/local&quot; options = &quot;-m0755&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">insinto /usr/local insopts -m0755 doins <span class="hljs-built_in">source</span> </code></pre> </li> <li> <p>When you want to install multiple files, specify sources all together.</p> <pre><code class="language-gn">install_config(&quot;install_init&quot;) { sources = [ &quot;init/initialize1.conf&quot;, &quot;init/initialize2.conf&quot;, ] install_path = &quot;upstart&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">insinto /etc/init doins init/initialize.conf </code></pre> </li> <li> <p>When you want to use <code>newins</code> command, specify new file name as <code>outputs</code>.</p> <pre><code class="language-gn">install_config(&quot;install_policy&quot;) { sources = [ &quot;policy/configuration.policy&quot; ] outputs = [ &quot;newfilename.policy&quot; ] install_path = &quot;seccomp_policy&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">insinto /usr/share/policy newins policy/configuration.policy newfilename.policy </code></pre> </li> <li> <p><code>outputs</code> are also used for installing multiple files.</p> <pre><code class="language-gn">install_config(&quot;install_multiple_new&quot;) { sources = [ &quot;old.policy&quot;, &quot;another_old.policy&quot;, ] outputs = [ &quot;new1.policy&quot;, &quot;new2.policy&quot;, ] install_path = &quot;seccomp_policy&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">insinto /usr/share/policy newins old.policy new1.policy newins another_old.policy new2.policy </code></pre> </li> <li> <p><code>symlinks</code> parameter is similar to <code>outputs</code>, but it creates symbolic link by <code>dosym</code>.</p> <pre><code class="language-gn">install_config(&quot;install_sym&quot;) { sources = [ &quot;source&quot; ] symlinks = [ &quot;symlink&quot; ] } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">dosym <span class="hljs-built_in">source</span> symlink </code></pre> </li> <li> <p>When <code>install_path</code> is specified, it is added to the head of <code>symlinks</code>.</p> <pre><code class="language-gn">install_config(&quot;install_sym&quot;) { sources = [ &quot;source&quot; ] symlinks = [ &quot;symlink&quot; ] install_path = &quot;/path/to/install&quot; } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">dosym <span class="hljs-built_in">source</span> /path/to/install/symlink </code></pre> </li> </ul> <h2 id="how-to-check-use-flags-in-gn" tabindex="-1"><a class="header-anchor" href="#how-to-check-use-flags-in-gn">How to check USE flags in GN</a></h2> <p>In GN files, USE flags can be referred as <code>use.foo</code>. (<a href="https://crrev.com/d2f92d07e9b0950157b7ce3a0f70cfee72fe76e7/hammerd/BUILD.gn#12">example</a>)</p> <p>Only allowed USE flags can be used. If you need to use new USE flags, update:</p> <ul> <li><code>_IUSE</code> constant in <code>platform2/common-mk/platform2.py</code> (<a href="https://crrev.com/c/1605185/5/common-mk/platform2.py">example</a>) <ul> <li>You will also need to add the new USE flag to your targeted packages' ebuild file. (<a href="https://crrev.com/c/3890515">example</a>)</li> <li>If you want the USE flag to work across packages, then you need to modify platform.eclass as well. (<a href="https://crrev.com/c/3599438">example</a>)</li> </ul> </li> <li><code>IUSE</code> variable in your ebuild file (<a href="https://crrev.com/c/1617184">example</a>)</li> </ul> <p>You can confirm that the USE flag is available for your package by running</p> <pre><code>equery-{board} uses {<span class="hljs-keyword">package</span>-name} </code></pre> <h2 id="how-to-write-unit-tests" tabindex="-1"><a class="header-anchor" href="#how-to-write-unit-tests">How to write unit tests</a></h2> <p><code>use.test</code> flag is set to true on unit testing. Enclose test only targets with <code>if (use.test) {}</code> to reduce compile time on production. The test targets are typically executables which depend on <code>//common-mk:test</code> to use gtest and gmock.</p> <p>How to run unit tests doesn't change: In chroot, run <code>cros_workon --board=$BOARD start $package_name</code> if you haven't. Then run</p> <pre><code><span class="hljs-attr">FEATURES</span>=test emerge-<span class="hljs-variable">$BOARD</span> <span class="hljs-variable">$package_name</span> </code></pre> <p>Prepend <code>VERBOSE=1</code> to see GN and ninja commands (plus other logs).</p> <h3 id="declaring-tests-in-buildgn" tabindex="-1"><a class="header-anchor" href="#declaring-tests-in-buildgn">Declaring tests in BUILD.gn</a></h3> <ul> <li> <p>A unit test executable can be run in the test phase by specifying <code>run_test = true</code> in the executable target.</p> <pre><code class="language-gn">executable(&quot;test_target&quot;) { sources = [ &quot;source.cc&quot; ] run_test = true } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">platform_test <span class="hljs-string">&quot;run&quot;</span> <span class="hljs-string">&quot;<span class="hljs-variable">${OUT}</span>/test_target&quot;</span> </code></pre> </li> <li> <p>When you want to specify config, you can use <code>test_config</code> variable.</p> <pre><code class="language-gn">executable(&quot;test_target&quot;) { sources = [ &quot;source.cc&quot; ] run_test = true test_config = { run_as_root = true gtest_filter = &quot;.RunAsRoot*-&quot; } } </code></pre> <p>is equivalent to</p> <pre><code class="language-bash">platform_test <span class="hljs-string">&quot;run&quot;</span> <span class="hljs-string">&quot;<span class="hljs-variable">${OUT}</span>/test_target&quot;</span> <span class="hljs-string">&quot;1&quot;</span> <span class="hljs-string">&quot;*.RunAsRoot*-&quot;</span> </code></pre> </li> </ul> <h2 id="faq" tabindex="-1"><a class="header-anchor" href="#faq">FAQ</a></h2> <h3 id="how-to-create-standalone-static-library" tabindex="-1"><a class="header-anchor" href="#how-to-create-standalone-static-library">How to create standalone static library?</a></h3> <p>Static libraries are compiled with thin archive enabled by default i.e. not standalone. Remove <code>use_thin_archive</code> from configs and add <code>nouse_thin_archive</code> to generate a standalone static library (<a href="https://chromium.googlesource.com/chromiumos/platform2/+/HEAD/glib-bridge/BUILD.gn#25">example</a>).</p> <p>TODO(crbug.com/991440): consider making standalone library the default and replace static_library with source_set whenever possible.</p> </main> </div> <script> // Configure Algolia search. let s = document.createElement('script'); s.src = '/_scripts/@docsearch/index.js'; document.head.append(s); window.addEventListener('load', () => { // Add the Algolia search widget. docsearch({ container: '#search', appId: 'RZDQYCCABX', apiKey: '98b0eabafeb13fe3e1af693d5713d8b4', indexName: 'chromium' }); }); // Configure Google Universal Analytics (the predecessor to GA4, we should // delete this when we don't need it any more). s = document.createElement('script'); s.src = 'https://www.googletagmanager.com/gtag/js?id=UA-5484340-1' s.async = true; document.head.append(s) window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'UA-5484340-1'); // Configure consent bar. s = document.createElement('script'); s.src = 'https://www.gstatic.com/brandstudio/kato/cookie_choice_component/cookie_consent_bar.v3.js' s.dataset.autoloadCookieConsentBar = true; s.dataset.autoloadCookieContentBarIntlCode = ''; document.head.append(s);</script>

Pages: 1 2 3 4 5 6 7 8 9 10