CINXE.COM
Rules Tutorial | Bazel
<!doctype html> <html lang="en" dir="ltr"> <head> <meta name="google-signin-client-id" content="157101835696-ooapojlodmuabs2do2vuhhnf90bccmoi.apps.googleusercontent.com"> <meta name="google-signin-scope" content="profile email https://www.googleapis.com/auth/developerprofiles https://www.googleapis.com/auth/developerprofiles.award"> <meta property="og:site_name" content="Bazel"> <meta property="og:type" content="website"><meta name="theme-color" content="#0c713a"><meta charset="utf-8"> <meta content="IE=Edge" http-equiv="X-UA-Compatible"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="manifest" href="/_pwa/bazel/manifest.json" crossorigin="use-credentials"> <link rel="preconnect" href="//www.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.gstatic.com" crossorigin> <link rel="preconnect" href="//fonts.googleapis.com" crossorigin> <link rel="preconnect" href="//apis.google.com" crossorigin> <link rel="preconnect" href="//www.google-analytics.com" crossorigin><link rel="stylesheet" href="//fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"> <link rel="stylesheet" href="//fonts.googleapis.com/css2?family=Material+Icons&family=Material+Symbols+Outlined&display=block"><link rel="stylesheet" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel/css/app.css"> <link rel="shortcut icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel/images/favicon-prod.png"> <link rel="apple-touch-icon" href="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel/images/touchicon-180.png"><link rel="canonical" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial"><link rel="search" type="application/opensearchdescription+xml" title="Bazel" href="https://bazel.build/s/opensearch.xml"> <link rel="alternate" hreflang="en" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial" /><link rel="alternate" hreflang="x-default" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial" /><link rel="alternate" hreflang="zh-Hans" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial?hl=zh-tw" /><link rel="alternate" hreflang="hi" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial?hl=hi" /><link rel="alternate" hreflang="id" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial?hl=id" /><link rel="alternate" hreflang="ja" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial?hl=ja" /><link rel="alternate" hreflang="ko" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial?hl=ko" /><link rel="alternate" hreflang="pt-BR" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial?hl=pt-br" /><link rel="alternate" hreflang="es-419" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial?hl=es-419" /><link rel="alternate" hreflang="th" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial?hl=th" /><link rel="alternate" hreflang="tr" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial?hl=tr" /><link rel="alternate" hreflang="vi" href="https://bazel.build/versions/7.4.0/rules/rules-tutorial?hl=vi" /><link rel="alternate" hreflang="en-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial" /><link rel="alternate" hreflang="x-default" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial" /><link rel="alternate" hreflang="zh-Hans-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial?hl=zh-cn" /><link rel="alternate" hreflang="zh-Hant-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial?hl=zh-tw" /><link rel="alternate" hreflang="hi-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial?hl=hi" /><link rel="alternate" hreflang="id-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial?hl=id" /><link rel="alternate" hreflang="ja-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial?hl=ja" /><link rel="alternate" hreflang="ko-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial?hl=ko" /><link rel="alternate" hreflang="pt-BR-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial?hl=pt-br" /><link rel="alternate" hreflang="es-419-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial?hl=es-419" /><link rel="alternate" hreflang="th-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial?hl=th" /><link rel="alternate" hreflang="tr-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial?hl=tr" /><link rel="alternate" hreflang="vi-cn" href="https://bazel.google.cn/versions/7.4.0/rules/rules-tutorial?hl=vi" /><title>Rules Tutorial | Bazel</title> <meta property="og:title" content="Rules Tutorial | Bazel"><meta property="og:url" content="https://bazel.build/versions/7.4.0/rules/rules-tutorial"><meta property="og:locale" content="en"><script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Article", "headline": "Rules Tutorial" } </script> <link rel="stylesheet" href="/extras.css"></head> <body class="" template="page" theme="bazel-theme" type="article" layout="docs" display-toc pending> <devsite-progress type="indeterminate" id="app-progress"></devsite-progress> <section class="devsite-wrapper"> <devsite-cookie-notification-bar></devsite-cookie-notification-bar><devsite-header role="banner"> <div class="devsite-header--inner nocontent"> <div class="devsite-top-logo-row-wrapper-wrapper"> <div class="devsite-top-logo-row-wrapper"> <div class="devsite-top-logo-row"> <button type="button" id="devsite-hamburger-menu" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Navigation menu button" visually-hidden aria-label="Open menu"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="bazel" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel/images/lockup.svg" class="devsite-site-logo" alt="Bazel"> </picture> </a> <span class="devsite-product-name"> <ul class="devsite-breadcrumb-list" > <li class="devsite-breadcrumb-item "> </li> </ul> </span> </div> <div class="devsite-top-logo-row-middle"> <div class="devsite-header-upper-tabs"> <devsite-tabs class="upper-tabs"> <nav class="devsite-tabs-wrapper" aria-label="Upper tabs"> <tab > <a href="https://bazel.build/versions/7.4.0/about" track-metadata-eventdetail="https://bazel.build/versions/7.4.0/about" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - about bazel" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: About Bazel" track-name="about bazel" > About Bazel </a> </tab> <tab > <a href="https://bazel.build/versions/7.4.0/start" track-metadata-eventdetail="https://bazel.build/versions/7.4.0/start" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - getting started" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Getting started" track-name="getting started" > Getting started </a> </tab> <tab > <a href="https://bazel.build/versions/7.4.0/docs" track-metadata-eventdetail="https://bazel.build/versions/7.4.0/docs" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - user guide" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: User guide" track-name="user guide" > User guide </a> </tab> <tab > <a href="https://bazel.build/versions/7.4.0/reference" track-metadata-eventdetail="https://bazel.build/versions/7.4.0/reference" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - reference" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Reference" track-name="reference" > Reference </a> </tab> <tab class="devsite-active"> <a href="https://bazel.build/versions/7.4.0/extending" track-metadata-eventdetail="https://bazel.build/versions/7.4.0/extending" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - extending" track-metadata-module="primary nav" aria-label="Extending, selected" data-category="Site-Wide Custom Events" data-label="Tab: Extending" track-name="extending" > Extending </a> </tab> <tab > <a href="https://bazel.build/versions/7.4.0/community" track-metadata-eventdetail="https://bazel.build/versions/7.4.0/community" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - community" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Community" track-name="community" > Community </a> </tab> <tab class="devsite-dropdown "> <a href="https://bazel.build/versions" track-metadata-eventdetail="https://bazel.build/versions" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - versions" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Versions" track-name="versions" > Versions </a> <a href="#" role="button" aria-haspopup="true" aria-expanded="false" aria-label="Dropdown menu for Versions" track-type="nav" track-metadata-eventdetail="https://bazel.build/versions" track-metadata-position="nav - versions" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Versions" track-name="versions" class="devsite-tabs-dropdown-toggle devsite-icon devsite-icon-arrow-drop-down"></a> <div class="devsite-tabs-dropdown" aria-label="submenu" hidden> <div class="devsite-tabs-dropdown-content"> <div class="devsite-tabs-dropdown-column "> <ul class="devsite-tabs-dropdown-section "> <li class="devsite-nav-item"> <a href="https://bazel.build/versions/7.4.0" track-type="nav" track-metadata-eventdetail="https://bazel.build/versions/7.4.0" track-metadata-position="nav - versions" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> 7.4 </div> </a> </li> <li class="devsite-nav-item"> <a href="https://bazel.build/versions/7.3.0" track-type="nav" track-metadata-eventdetail="https://bazel.build/versions/7.3.0" track-metadata-position="nav - versions" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> 7.3 </div> </a> </li> <li class="devsite-nav-item"> <a href="https://bazel.build/versions/7.2.0" track-type="nav" track-metadata-eventdetail="https://bazel.build/versions/7.2.0" track-metadata-position="nav - versions" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> 7.2 </div> </a> </li> <li class="devsite-nav-item"> <a href="https://bazel.build/versions/7.1.0" track-type="nav" track-metadata-eventdetail="https://bazel.build/versions/7.1.0" track-metadata-position="nav - versions" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> 7.1 </div> </a> </li> <li class="devsite-nav-item"> <a href="https://bazel.build/versions/7.0.0" track-type="nav" track-metadata-eventdetail="https://bazel.build/versions/7.0.0" track-metadata-position="nav - versions" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> 7.0 </div> </a> </li> <li class="devsite-nav-item"> <a href="https://bazel.build/versions/6.5.0" track-type="nav" track-metadata-eventdetail="https://bazel.build/versions/6.5.0" track-metadata-position="nav - versions" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> 6.5 </div> </a> </li> <li class="devsite-nav-item"> <a href="https://docs.bazel.build/versions/5.4.1/bazel-overview.html" track-type="nav" track-metadata-eventdetail="https://docs.bazel.build/versions/5.4.1/bazel-overview.html" track-metadata-position="nav - versions" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> 5.4.1 </div> </a> </li> </ul> </div> <div class="devsite-tabs-dropdown-column "> <ul class="devsite-tabs-dropdown-section "> <li class="devsite-nav-item"> <a href="https://bazel.build/" track-type="nav" track-metadata-eventdetail="https://bazel.build/" track-metadata-position="nav - versions" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> Nightly </div> </a> </li> <li class="devsite-nav-item"> <a href="https://bazel.build/versions" track-type="nav" track-metadata-eventdetail="https://bazel.build/versions" track-metadata-position="nav - versions" track-metadata-module="tertiary nav" tooltip > <div class="devsite-nav-item-title"> More… </div> </a> </li> </ul> </div> </div> </div> </tab> </nav> </devsite-tabs> </div> <devsite-search enable-signin enable-search enable-suggestions enable-query-completion project-name="Bazel" tenant-name="Bazel" > <form class="devsite-search-form" action="https://bazel.build/s/results" method="GET"> <div class="devsite-search-container"> <button type="button" search-open class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Open search"></button> <div class="devsite-searchbox"> <input aria-activedescendant="" aria-autocomplete="list" aria-label="Search" aria-expanded="false" aria-haspopup="listbox" autocomplete="off" class="devsite-search-field devsite-search-query" name="q" placeholder="Search" role="combobox" type="text" value="" > <div class="devsite-search-image material-icons" aria-hidden="true"> </div> <div class="devsite-search-shortcut-icon-container" aria-hidden="true"> <kbd class="devsite-search-shortcut-icon">/</kbd> </div> </div> </div> </form> <button type="button" search-close class="devsite-search-button devsite-header-icon-button button-flat material-icons" aria-label="Close search"></button> </devsite-search> </div> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> <a class="devsite-header-link devsite-top-button button gc-analytics-event" href="//github.com/bazelbuild/bazel/" data-category="Site-Wide Custom Events" data-label="Site header link" > GitHub </a> <devsite-user enable-profiles id="devsite-user"> <span class="button devsite-top-button" aria-hidden="true" visually-hidden>Sign in</span> </devsite-user> </div> </div> </div> <div class="devsite-collapsible-section "> <div class="devsite-header-background"> <div class="devsite-product-id-row" > <div class="devsite-product-description-row"> <ul class="devsite-breadcrumb-list" > <li class="devsite-breadcrumb-item "> <a href="https://bazel.build/versions/7.4.0/extending" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Lower Header" data-value="1" track-type="globalNav" track-name="breadcrumb" track-metadata-position="1" track-metadata-eventdetail="" > Guides to maximize Bazel's power through advanced concepts and extensions </a> </li> </ul> </div> </div> <div class="devsite-doc-set-nav-row"> <devsite-tabs class="lower-tabs"> <nav class="devsite-tabs-wrapper" aria-label="Lower tabs"> <tab > <a href="https://bazel.build/versions/7.4.0/extending/concepts" track-metadata-eventdetail="https://bazel.build/versions/7.4.0/extending/concepts" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - concepts" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Concepts" track-name="concepts" > Concepts </a> </tab> <tab class="devsite-active"> <a href="https://bazel.build/versions/7.4.0/rules/rules-tutorial" track-metadata-eventdetail="https://bazel.build/versions/7.4.0/rules/rules-tutorial" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - writing rules" track-metadata-module="primary nav" aria-label="Writing rules, selected" data-category="Site-Wide Custom Events" data-label="Tab: Writing rules" track-name="writing rules" > Writing rules </a> </tab> <tab > <a href="https://bazel.build/versions/7.4.0/rules/testing" track-metadata-eventdetail="https://bazel.build/versions/7.4.0/rules/testing" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - distributing rules" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: Distributing rules" track-name="distributing rules" > Distributing rules </a> </tab> <tab > <a href="https://bazel.build/versions/7.4.0/rules/lib/overview" track-metadata-eventdetail="https://bazel.build/versions/7.4.0/rules/lib/overview" class="devsite-tabs-content gc-analytics-event " track-type="nav" track-metadata-position="nav - apis" track-metadata-module="primary nav" data-category="Site-Wide Custom Events" data-label="Tab: APIs" track-name="apis" > APIs </a> </tab> </nav> </devsite-tabs> </div> </div> </div> </div> </devsite-header> <devsite-book-nav scrollbars > <div class="devsite-book-nav-filter" > <span class="filter-list-icon material-icons" aria-hidden="true"></span> <input type="text" placeholder="Filter" aria-label="Type to filter" role="searchbox"> <span class="filter-clear-button hidden" data-title="Clear filter" aria-label="Clear filter" role="button" tabindex="0"></span> </div> <nav class="devsite-book-nav devsite-nav nocontent" aria-label="Side menu"> <div class="devsite-mobile-header"> <button type="button" id="devsite-close-nav" class="devsite-header-icon-button button-flat material-icons gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Close navigation" aria-label="Close navigation"> </button> <div class="devsite-product-name-wrapper"> <a href="/" class="devsite-site-logo-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Site logo" track-type="globalNav" track-name="bazel" track-metadata-position="nav" track-metadata-eventDetail="nav"> <picture> <img src="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel/images/lockup.svg" class="devsite-site-logo" alt="Bazel"> </picture> </a> <span class="devsite-product-name"> <ul class="devsite-breadcrumb-list" > <li class="devsite-breadcrumb-item "> </li> </ul> </span> </div> </div> <div class="devsite-book-nav-wrapper"> <div class="devsite-mobile-nav-top"> <ul class="devsite-nav-list"> <li class="devsite-nav-item"> <a href="/versions/7.4.0/about" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: About Bazel" track-name="about bazel" data-category="Site-Wide Custom Events" data-label="Responsive Tab: About Bazel" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > About Bazel </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/7.4.0/start" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Getting started" track-name="getting started" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Getting started" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Getting started </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/7.4.0/docs" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: User guide" track-name="user guide" data-category="Site-Wide Custom Events" data-label="Responsive Tab: User guide" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > User guide </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/7.4.0/reference" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Reference" track-name="reference" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Reference" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Reference </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/7.4.0/extending" class="devsite-nav-title gc-analytics-event devsite-nav-active" data-category="Site-Wide Custom Events" data-label="Tab: Extending" track-name="extending" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Extending" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Extending </span> </a> <ul class="devsite-nav-responsive-tabs"> <li class="devsite-nav-item"> <a href="/versions/7.4.0/extending/concepts" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Concepts" track-name="concepts" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Concepts" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Concepts </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/7.4.0/rules/rules-tutorial" class="devsite-nav-title gc-analytics-event devsite-nav-has-children devsite-nav-active" data-category="Site-Wide Custom Events" data-label="Tab: Writing rules" track-name="writing rules" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Writing rules" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip menu="_book"> Writing rules </span> <span class="devsite-nav-icon material-icons" data-icon="forward" menu="_book"> </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/7.4.0/rules/testing" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: Distributing rules" track-name="distributing rules" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Distributing rules" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Distributing rules </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/7.4.0/rules/lib/overview" class="devsite-nav-title gc-analytics-event devsite-nav-has-children " data-category="Site-Wide Custom Events" data-label="Tab: APIs" track-name="apis" data-category="Site-Wide Custom Events" data-label="Responsive Tab: APIs" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > APIs </span> <span class="devsite-nav-icon material-icons" data-icon="forward" > </span> </a> </li> </ul> </li> <li class="devsite-nav-item"> <a href="/versions/7.4.0/community" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Community" track-name="community" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Community" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Community </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Tab: Versions" track-name="versions" data-category="Site-Wide Custom Events" data-label="Responsive Tab: Versions" track-type="globalNav" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Versions </span> </a> <ul class="devsite-nav-responsive-tabs devsite-nav-has-menu "> <li class="devsite-nav-item"> <span class="devsite-nav-title" tooltip data-category="Site-Wide Custom Events" data-label="Tab: Versions" track-name="versions" > <span class="devsite-nav-text" tooltip menu="Versions"> More </span> <span class="devsite-nav-icon material-icons" data-icon="forward" menu="Versions"> </span> </span> </li> </ul> </li> <li class="devsite-nav-item"> <a href="//github.com/bazelbuild/bazel/" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: GitHub" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > GitHub </span> </a> </li> </ul> </div> <div class="devsite-mobile-nav-bottom"> <ul class="devsite-nav-list" menu="_book"> <li class="devsite-nav-item"><a href="/versions/7.4.0/rules/rules-tutorial" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /versions/7.4.0/rules/rules-tutorial" track-type="bookNav" track-name="click" track-metadata-eventdetail="/versions/7.4.0/rules/rules-tutorial" ><span class="devsite-nav-text" tooltip>Creating a rule</span></a></li> <li class="devsite-nav-item"><a href="/versions/7.4.0/rules/macro-tutorial" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /versions/7.4.0/rules/macro-tutorial" track-type="bookNav" track-name="click" track-metadata-eventdetail="/versions/7.4.0/rules/macro-tutorial" ><span class="devsite-nav-text" tooltip>Creating a macro</span></a></li> <li class="devsite-nav-item"><a href="/versions/7.4.0/rules/verbs-tutorial" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /versions/7.4.0/rules/verbs-tutorial" track-type="bookNav" track-name="click" track-metadata-eventdetail="/versions/7.4.0/rules/verbs-tutorial" ><span class="devsite-nav-text" tooltip>Creating custom verbs</span></a></li> <li class="devsite-nav-item"><a href="/versions/7.4.0/rules/language" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /versions/7.4.0/rules/language" track-type="bookNav" track-name="click" track-metadata-eventdetail="/versions/7.4.0/rules/language" ><span class="devsite-nav-text" tooltip>Starlark language</span></a></li> <li class="devsite-nav-item"><a href="/versions/7.4.0/rules/bzl-style" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /versions/7.4.0/rules/bzl-style" track-type="bookNav" track-name="click" track-metadata-eventdetail="/versions/7.4.0/rules/bzl-style" ><span class="devsite-nav-text" tooltip>Starlark style guide</span></a></li> <li class="devsite-nav-item"><a href="/versions/7.4.0/rules/challenges" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /versions/7.4.0/rules/challenges" track-type="bookNav" track-name="click" track-metadata-eventdetail="/versions/7.4.0/rules/challenges" ><span class="devsite-nav-text" tooltip>Challenges</span></a></li> <li class="devsite-nav-item"><a href="/versions/7.4.0/rules/windows" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: /versions/7.4.0/rules/windows" track-type="bookNav" track-name="click" track-metadata-eventdetail="/versions/7.4.0/rules/windows" ><span class="devsite-nav-text" tooltip>Writing rules for Windows</span></a></li> <li class="devsite-nav-item devsite-nav-external"><a href="https://github.com/bazelbuild/examples/tree/HEAD/rules" class="devsite-nav-title gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Book nav link, pathname: https://github.com/bazelbuild/examples/tree/HEAD/rules" track-type="bookNav" track-name="click" track-metadata-eventdetail="https://github.com/bazelbuild/examples/tree/HEAD/rules" ><span class="devsite-nav-text" tooltip>Example rules</span><span class="devsite-nav-icon material-icons" data-icon="external" data-title="External" aria-hidden="true"></span></a></li> </ul> <ul class="devsite-nav-list" menu="Versions" aria-label="Side menu" hidden> <li class="devsite-nav-item"> <a href="/versions/7.4.0" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: 7.4" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > 7.4 </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/7.3.0" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: 7.3" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > 7.3 </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/7.2.0" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: 7.2" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > 7.2 </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/7.1.0" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: 7.1" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > 7.1 </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/7.0.0" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: 7.0" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > 7.0 </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions/6.5.0" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: 6.5" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > 6.5 </span> </a> </li> <li class="devsite-nav-item"> <a href="https://docs.bazel.build/versions/5.4.1/bazel-overview.html" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: 5.4.1" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > 5.4.1 </span> </a> </li> <li class="devsite-nav-item"> <a href="/" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: Nightly" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > Nightly </span> </a> </li> <li class="devsite-nav-item"> <a href="/versions" class="devsite-nav-title gc-analytics-event " data-category="Site-Wide Custom Events" data-label="Responsive Tab: More…" track-type="navMenu" track-metadata-eventDetail="globalMenu" track-metadata-position="nav"> <span class="devsite-nav-text" tooltip > More… </span> </a> </li> </ul> </div> </div> </nav> </devsite-book-nav> <section id="gc-wrapper"> <main role="main" class="devsite-main-content" has-book-nav has-sidebar > <div class="devsite-sidebar"> <div class="devsite-sidebar-content"> <devsite-toc class="devsite-nav" role="navigation" aria-label="On this page" depth="2" scrollbars ></devsite-toc> <devsite-recommendations-sidebar class="nocontent devsite-nav"> </devsite-recommendations-sidebar> </div> </div> <devsite-content> <article class="devsite-article"> <div class="devsite-article-meta nocontent" role="navigation"> <ul class="devsite-breadcrumb-list" aria-label="Breadcrumb"> <li class="devsite-breadcrumb-item "> <a href="https://bazel.build/" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="1" track-type="globalNav" track-name="breadcrumb" track-metadata-position="1" track-metadata-eventdetail="Bazel" > Bazel </a> </li> <li class="devsite-breadcrumb-item "> <div class="devsite-breadcrumb-guillemet material-icons" aria-hidden="true"></div> <a href="https://bazel.build/versions/7.4.0/extending" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="2" track-type="globalNav" track-name="breadcrumb" track-metadata-position="2" track-metadata-eventdetail="" > Extending </a> </li> <li class="devsite-breadcrumb-item "> <div class="devsite-breadcrumb-guillemet material-icons" aria-hidden="true"></div> <a href="https://bazel.build/versions/7.4.0/rules/rules-tutorial" class="devsite-breadcrumb-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Breadcrumbs" data-value="3" track-type="globalNav" track-name="breadcrumb" track-metadata-position="3" track-metadata-eventdetail="" > Writing rules </a> </li> </ul> <devsite-thumb-rating position="header"> </devsite-thumb-rating> </div> <devsite-feedback position="header" project-name="Bazel" product-id="5052038" bucket="https-bazel-build" context="" version="t-devsite-webserver-20241114-r00-rc02.464921008191574316" data-label="Send Feedback Button" track-type="feedback" track-name="sendFeedbackLink" track-metadata-position="header" class="nocontent" project-icon="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel/images/touchicon-180.png" > <button> Send feedback </button> </devsite-feedback> <h1 class="devsite-page-title" tabindex="-1"> Rules Tutorial </h1> <devsite-feature-tooltip ack-key="AckCollectionsBookmarkTooltipDismiss" analytics-category="Site-Wide Custom Events" analytics-action-show="Callout Profile displayed" analytics-action-close="Callout Profile dismissed" analytics-label="Create Collection Callout" class="devsite-page-bookmark-tooltip nocontent" dismiss-button="true" id="devsite-collections-dropdown" dismiss-button-text="Dismiss" close-button-text="Got it"> <devsite-bookmark></devsite-bookmark> <span slot="popout-heading"> Stay organized with collections </span> <span slot="popout-contents"> Save and categorize content based on your preferences. </span> </devsite-feature-tooltip> <div class="devsite-page-title-meta"><devsite-view-release-notes></devsite-view-release-notes></div> <devsite-toc class="devsite-nav" depth="2" devsite-toc-embedded > </devsite-toc> <div class="devsite-article-body clearfix "> <a class="button button-with-icon" href="https://github.com/bazelbuild/bazel/issues/new?title=%5Bbazel.build%5D+Problem+with+/versions/7.4.0/rules/rules-tutorial&template=doc_issue.yml&link=https%3A%2F%2Fbazel.build/versions/7.4.0/rules/rules-tutorial" target="_blank"> Report an issue<span class="material-icons icon-after" aria-hidden="true" translate="no">open_in_new</span> </a> <a class="button button-with-icon" href="https://github.com/bazelbuild/bazel/tree/master/site/en/versions/7.4.0/rules/rules-tutorial.md" target="_blank"> View source<span class="material-icons icon-after" aria-hidden="true" translate="no">open_in_new</span> </a> <span style="float: right; line-height: 36px"> <a href="/rules/rules-tutorial">Nightly</a> <!-- The lines below are updated by //scripts/docs:gen_new_toc --> <!-- BEGIN_VERSION_INDICATOR --> · <strong>7.4</strong> . <a href="/versions/7.3.0/rules/rules-tutorial">7.3</a> · <a href="/versions/7.2.0/rules/rules-tutorial">7.2</a> · <a href="/versions/7.1.0/rules/rules-tutorial">7.1</a> · <a href="/versions/7.0.0/rules/rules-tutorial">7.0</a> · <a href="/versions/6.5.0/rules/rules-tutorial">6.5</a> <!-- END_VERSION_INDICATOR --> </span> <p/> <!-- [TOC] --> <p><a href="https://github.com/bazelbuild/starlark">Starlark</a> is a Python-like configuration language originally developed for use in Bazel and since adopted by other tools. Bazel's <code translate="no" dir="ltr">BUILD</code> and <code translate="no" dir="ltr">.bzl</code> files are written in a dialect of Starlark properly known as the "Build Language", though it is often simply referred to as "Starlark", especially when emphasizing that a feature is expressed in the Build Language as opposed to being a built-in or "native" part of Bazel. Bazel augments the core language with numerous build-related functions such as <code translate="no" dir="ltr">glob</code>, <code translate="no" dir="ltr">genrule</code>, <code translate="no" dir="ltr">java_binary</code>, and so on.</p> <p>See the <a href="/versions/7.4.0/start">Bazel</a> and <a href="/versions/7.4.0/extending/concepts">Starlark</a> documentation for more details, and the <a href="https://github.com/bazel-contrib/rules-template">Rules SIG template</a> as a starting point for new rulesets.</p> <h2 id="the_empty_rule" data-text="The empty rule" tabindex="-1">The empty rule</h2> <p>To create your first rule, create the file <code translate="no" dir="ltr">foo.bzl</code>:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">def _foo_binary_impl(ctx): pass foo_binary = rule( implementation = _foo_binary_impl, ) </code></pre> <p>When you call the <a href="/versions/7.4.0/rules/lib/globals#rule"><code translate="no" dir="ltr">rule</code></a> function, you must define a callback function. The logic will go there, but you can leave the function empty for now. The <a href="/versions/7.4.0/rules/lib/ctx"><code translate="no" dir="ltr">ctx</code></a> argument provides information about the target.</p> <p>You can load the rule and use it from a <code translate="no" dir="ltr">BUILD</code> file.</p> <p>Create a <code translate="no" dir="ltr">BUILD</code> file in the same directory:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">load(":foo.bzl", "foo_binary") foo_binary(name = "bin") </code></pre> <p>Now, the target can be built:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">$ bazel build bin INFO: Analyzed target //:bin (2 packages loaded, 17 targets configured). INFO: Found 1 target... Target //:bin up-to-date (nothing to build) </code></pre> <p>Even though the rule does nothing, it already behaves like other rules: it has a mandatory name, it supports common attributes like <code translate="no" dir="ltr">visibility</code>, <code translate="no" dir="ltr">testonly</code>, and <code translate="no" dir="ltr">tags</code>.</p> <h2 id="evaluation_model" data-text="Evaluation model" tabindex="-1">Evaluation model</h2> <p>Before going further, it's important to understand how the code is evaluated.</p> <p>Update <code translate="no" dir="ltr">foo.bzl</code> with some print statements:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">def _foo_binary_impl(ctx): print("analyzing", ctx.label) foo_binary = rule( implementation = _foo_binary_impl, ) print("bzl file evaluation") </code></pre> <p>and BUILD:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">load(":foo.bzl", "foo_binary") print("BUILD file") foo_binary(name = "bin1") foo_binary(name = "bin2") </code></pre> <p><a href="/versions/7.4.0/rules/lib/ctx#label"><code translate="no" dir="ltr">ctx.label</code></a> corresponds to the label of the target being analyzed. The <code translate="no" dir="ltr">ctx</code> object has many useful fields and methods; you can find an exhaustive list in the <a href="/versions/7.4.0/rules/lib/ctx">API reference</a>.</p> <p>Query the code:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">$ bazel query :all DEBUG: /usr/home/bazel-codelab/foo.bzl:8:1: bzl file evaluation DEBUG: /usr/home/bazel-codelab/BUILD:2:1: BUILD file //:bin2 //:bin1 </code></pre> <p>Make a few observations:</p> <ul> <li>"bzl file evaluation" is printed first. Before evaluating the <code translate="no" dir="ltr">BUILD</code> file, Bazel evaluates all the files it loads. If multiple <code translate="no" dir="ltr">BUILD</code> files are loading foo.bzl, you would see only one occurrence of "bzl file evaluation" because Bazel caches the result of the evaluation.</li> <li>The callback function <code translate="no" dir="ltr">_foo_binary_impl</code> is not called. Bazel query loads <code translate="no" dir="ltr">BUILD</code> files, but doesn't analyze targets.</li> </ul> <p>To analyze the targets, use the <a href="/versions/7.4.0/query/cquery"><code translate="no" dir="ltr">cquery</code></a> ("configured query") or the <code translate="no" dir="ltr">build</code> command:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">$ bazel build :all DEBUG: /usr/home/bazel-codelab/foo.bzl:2:5: analyzing //:bin1 DEBUG: /usr/home/bazel-codelab/foo.bzl:2:5: analyzing //:bin2 INFO: Analyzed 2 targets (0 packages loaded, 0 targets configured). INFO: Found 2 targets... </code></pre> <p>As you can see, <code translate="no" dir="ltr">_foo_binary_impl</code> is now called twice - once for each target.</p> <p>Notice that neither "bzl file evaluation" nor "BUILD file" are printed again, because the evaluation of <code translate="no" dir="ltr">foo.bzl</code> is cached after the call to <code translate="no" dir="ltr">bazel query</code>. Bazel only emits <code translate="no" dir="ltr">print</code> statements when they are actually executed.</p> <h2 id="creating_a_file" data-text="Creating a file" tabindex="-1">Creating a file</h2> <p>To make your rule more useful, update it to generate a file. First, declare the file and give it a name. In this example, create a file with the same name as the target:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">ctx.actions.declare_file(ctx.label.name) </code></pre> <p>If you run <code translate="no" dir="ltr">bazel build :all</code> now, you will get an error:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">The following files have no generating action: bin2 </code></pre> <p>Whenever you declare a file, you have to tell Bazel how to generate it by creating an action. Use <a href="/versions/7.4.0/rules/lib/actions#write"><code translate="no" dir="ltr">ctx.actions.write</code></a>, to create a file with the given content.</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">def _foo_binary_impl(ctx): out = ctx.actions.declare_file(ctx.label.name) ctx.actions.write( output = out, content = "Hello\n", ) </code></pre> <p>The code is valid, but it won't do anything:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">$ bazel build bin1 Target //:bin1 up-to-date (nothing to build) </code></pre> <p>The <code translate="no" dir="ltr">ctx.actions.write</code> function registered an action, which taught Bazel how to generate the file. But Bazel won't create the file until it is actually requested. So the last thing to do is tell Bazel that the file is an output of the rule, and not a temporary file used within the rule implementation.</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">def _foo_binary_impl(ctx): out = ctx.actions.declare_file(ctx.label.name) ctx.actions.write( output = out, content = "Hello!\n", ) return [DefaultInfo(files = depset([out]))] </code></pre> <p>Look at the <code translate="no" dir="ltr">DefaultInfo</code> and <code translate="no" dir="ltr">depset</code> functions later. For now, assume that the last line is the way to choose the outputs of a rule.</p> <p>Now, run Bazel:</p> <pre class="prettyprint" translate="no" dir="ltr"><code translate="no" dir="ltr">$ bazel build bin1 INFO: Found 1 target... Target //:bin1 up-to-date: bazel-bin/bin1 $ cat bazel-bin/bin1 Hello! </code></pre> <p>You have successfully generated a file!</p> <h2 id="attributes" data-text="Attributes" tabindex="-1">Attributes</h2> <p>To make the rule more useful, add new attributes using <a href="/versions/7.4.0/rules/lib/attr">the <code translate="no" dir="ltr">attr</code> module</a> and update the rule definition.</p> <p>Add a string attribute called <code translate="no" dir="ltr">username</code>:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">foo_binary = rule( implementation = _foo_binary_impl, attrs = { "username": attr.string(), }, ) </code></pre> <p>Next, set it in the <code translate="no" dir="ltr">BUILD</code> file:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">foo_binary( name = "bin", username = "Alice", ) </code></pre> <p>To access the value in the callback function, use <code translate="no" dir="ltr">ctx.attr.username</code>. For example:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">def _foo_binary_impl(ctx): out = ctx.actions.declare_file(ctx.label.name) ctx.actions.write( output = out, content = "Hello {}!\n".format(ctx.attr.username), ) return [DefaultInfo(files = depset([out]))] </code></pre> <p>Note that you can make the attribute mandatory or set a default value. Look at the documentation of <a href="/versions/7.4.0/rules/lib/attr#string"><code translate="no" dir="ltr">attr.string</code></a>. You may also use other types of attributes, such as <a href="/versions/7.4.0/rules/lib/attr#bool">boolean</a> or <a href="/versions/7.4.0/rules/lib/attr#int_list">list of integers</a>.</p> <h2 id="dependencies" data-text="Dependencies" tabindex="-1">Dependencies</h2> <p>Dependency attributes, such as <a href="/versions/7.4.0/rules/lib/attr#label"><code translate="no" dir="ltr">attr.label</code></a> and <a href="/versions/7.4.0/rules/lib/attr#label_list"><code translate="no" dir="ltr">attr.label_list</code></a>, declare a dependency from the target that owns the attribute to the target whose label appears in the attribute's value. This kind of attribute forms the basis of the target graph.</p> <p>In the <code translate="no" dir="ltr">BUILD</code> file, the target label appears as a string object, such as <code translate="no" dir="ltr">//pkg:name</code>. In the implementation function, the target will be accessible as a <a href="/versions/7.4.0/rules/lib/Target"><code translate="no" dir="ltr">Target</code></a> object. For example, view the files returned by the target using <a href="/versions/7.4.0/rules/lib/Target#modules.Target.files"><code translate="no" dir="ltr">Target.files</code></a>.</p> <h3 id="multiple_files" data-text="Multiple files" tabindex="-1">Multiple files</h3> <p>By default, only targets created by rules may appear as dependencies (such as a <code translate="no" dir="ltr">foo_library()</code> target). If you want the attribute to accept targets that are input files (such as source files in the repository), you can do it with <code translate="no" dir="ltr">allow_files</code> and specify the list of accepted file extensions (or <code translate="no" dir="ltr">True</code> to allow any file extension):</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">"srcs": attr.label_list(allow_files = [".java"]), </code></pre> <p>The list of files can be accessed with <code translate="no" dir="ltr">ctx.files.<attribute name></code>. For example, the list of files in the <code translate="no" dir="ltr">srcs</code> attribute can be accessed through</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">ctx.files.srcs </code></pre> <h3 id="single_file" data-text="Single file" tabindex="-1">Single file</h3> <p>If you need only one file, use <code translate="no" dir="ltr">allow_single_file</code>:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">"src": attr.label(allow_single_file = [".java"]) </code></pre> <p>This file is then accessible under <code translate="no" dir="ltr">ctx.file.<attribute name></code>:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">ctx.file.src </code></pre> <h2 id="create_a_file_with_a_template" data-text="Create a file with a template" tabindex="-1">Create a file with a template</h2> <p>You can create a rule that generates a .cc file based on a template. Also, you can use <code translate="no" dir="ltr">ctx.actions.write</code> to output a string constructed in the rule implementation function, but this has two problems. First, as the template gets bigger, it becomes more memory efficient to put it in a separate file and avoid constructing large strings during the analysis phase. Second, using a separate file is more convenient for the user. Instead, use <a href="/versions/7.4.0/rules/lib/actions#expand_template"><code translate="no" dir="ltr">ctx.actions.expand_template</code></a>, which performs substitutions on a template file.</p> <p>Create a <code translate="no" dir="ltr">template</code> attribute to declare a dependency on the template file:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">def _hello_world_impl(ctx): out = ctx.actions.declare_file(ctx.label.name + ".cc") ctx.actions.expand_template( output = out, template = ctx.file.template, substitutions = {"{NAME}": ctx.attr.username}, ) return [DefaultInfo(files = depset([out]))] hello_world = rule( implementation = _hello_world_impl, attrs = { "username": attr.string(default = "unknown person"), "template": attr.label( allow_single_file = [".cc.tpl"], mandatory = True, ), }, ) </code></pre> <p>Users can use the rule like this:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">hello_world( name = "hello", username = "Alice", template = "file.cc.tpl", ) cc_binary( name = "hello_bin", srcs = [":hello"], ) </code></pre> <p>If you don't want to expose the template to the end-user and always use the same one, you can set a default value and make the attribute private:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr"> "_template": attr.label( allow_single_file = True, default = "file.cc.tpl", ), </code></pre> <p>Attributes that start with an underscore are private and cannot be set in a <code translate="no" dir="ltr">BUILD</code> file. The template is now an <em>implicit dependency</em>: Every <code translate="no" dir="ltr">hello_world</code> target has a dependency on this file. Don't forget to make this file visible to other packages by updating the <code translate="no" dir="ltr">BUILD</code> file and using <a href="/versions/7.4.0/reference/be/functions#exports_files"><code translate="no" dir="ltr">exports_files</code></a>:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">exports_files(["file.cc.tpl"]) </code></pre> <h2 id="going_further" data-text="Going further" tabindex="-1">Going further</h2> <ul> <li>Take a look at the <a href="/versions/7.4.0/extending/rules#contents">reference documentation for rules</a>.</li> <li>Get familiar with <a href="/versions/7.4.0/extending/depsets">depsets</a>.</li> <li>Check out the <a href="https://github.com/bazelbuild/examples/tree/master/rules">examples repository</a> which includes additional examples of rules.</li> </ul> </div> <devsite-thumb-rating position="footer"> </devsite-thumb-rating> <devsite-feedback position="footer" project-name="Bazel" product-id="5052038" bucket="https-bazel-build" context="" version="t-devsite-webserver-20241114-r00-rc02.464921008191574316" data-label="Send Feedback Button" track-type="feedback" track-name="sendFeedbackLink" track-metadata-position="footer" class="nocontent" project-icon="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel/images/touchicon-180.png" > <button> Send feedback </button> </devsite-feedback> <div class="devsite-floating-action-buttons"> </div> </article> <devsite-content-footer class="nocontent"> <p>Except as otherwise noted, the content of this page is licensed under the <a href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 License</a>, and code samples are licensed under the <a href="https://www.apache.org/licenses/LICENSE-2.0">Apache 2.0 License</a>. For details, see the <a href="https://developers.google.com/site-policies">Google Developers Site Policies</a>. Java is a registered trademark of Oracle and/or its affiliates.</p> <p>Last updated 2024-10-22 UTC.</p> </devsite-content-footer> <devsite-notification > </devsite-notification> <div class="devsite-content-data"> <template class="devsite-thumb-rating-feedback"> <devsite-feedback position="thumb-rating" project-name="Bazel" product-id="5052038" bucket="https-bazel-build" context="" version="t-devsite-webserver-20241114-r00-rc02.464921008191574316" data-label="Send Feedback Button" track-type="feedback" track-name="sendFeedbackLink" track-metadata-position="thumb-rating" class="nocontent" project-icon="https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel/images/touchicon-180.png" > <button> Need to tell us more? </button> </devsite-feedback> </template> <template class="devsite-content-data-template"> [[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2024-10-22 UTC."],[],[]] </template> </div> </devsite-content> </main> <devsite-footer-promos class="devsite-footer"> </devsite-footer-promos> <devsite-footer-linkboxes class="devsite-footer"> <nav class="devsite-footer-linkboxes nocontent" aria-label="Footer links"> <ul class="devsite-footer-linkboxes-list"> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">About</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="/community/users" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Who's using Bazel </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/contribute/" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Contribute </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/contribute/contribution-policy" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Governance model </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/release" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Release model </a> </li> <li class="devsite-footer-linkbox-item"> <a href="/brand" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 5)" > Brand guidelines </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Stay connected</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="//blog.bazel.build" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Blog </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//github.com/bazelbuild/bazel" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > GitHub </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//twitter.com/bazelbuild" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Twitter </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//youtube.com/user/googleOSPO" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > YouTube </a> </li> </ul> </li> <li class="devsite-footer-linkbox "> <h3 class="devsite-footer-linkbox-heading no-link">Support</h3> <ul class="devsite-footer-linkbox-list"> <li class="devsite-footer-linkbox-item"> <a href="/help" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 1)" > Support </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//github.com/bazelbuild/bazel/issues" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 2)" > Issue tracker </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//slack.bazel.build" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 3)" > Slack </a> </li> <li class="devsite-footer-linkbox-item"> <a href="//stackoverflow.com/questions/tagged/bazel" class="devsite-footer-linkbox-link gc-analytics-event" data-category="Site-Wide Custom Events" data-label="Footer Link (index 4)" > Stack Overflow </a> </li> </ul> </li> </ul> </nav> </devsite-footer-linkboxes> <devsite-footer-utility class="devsite-footer"> <div class="devsite-footer-utility nocontent"> <nav class="devsite-footer-utility-links" aria-label="Utility links"> <ul class="devsite-footer-utility-list"> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//policies.google.com/terms" data-category="Site-Wide Custom Events" data-label="Footer Terms link" > Terms </a> </li> <li class="devsite-footer-utility-item "> <a class="devsite-footer-utility-link gc-analytics-event" href="//policies.google.com/privacy" data-category="Site-Wide Custom Events" data-label="Footer Privacy link" > Privacy </a> </li> <li class="devsite-footer-utility-item glue-cookie-notification-bar-control"> <a class="devsite-footer-utility-link gc-analytics-event" href="#" data-category="Site-Wide Custom Events" data-label="Footer Manage cookies link" aria-hidden="true" > Manage cookies </a> </li> </ul> <devsite-language-selector> <ul role="presentation"> <li role="presentation"> <a role="menuitem" lang="en" >English</a> </li> <li role="presentation"> <a role="menuitem" lang="es_419" >Español – América Latina</a> </li> <li role="presentation"> <a role="menuitem" lang="id" >Indonesia</a> </li> <li role="presentation"> <a role="menuitem" lang="pt_br" >Português – Brasil</a> </li> <li role="presentation"> <a role="menuitem" lang="vi" >Tiếng Việt</a> </li> <li role="presentation"> <a role="menuitem" lang="tr" >Türkçe</a> </li> <li role="presentation"> <a role="menuitem" lang="hi" >हिंदी</a> </li> <li role="presentation"> <a role="menuitem" lang="th" >ภาษาไทย</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_cn" >中文 – 简体</a> </li> <li role="presentation"> <a role="menuitem" lang="zh_tw" >中文 – 繁體</a> </li> <li role="presentation"> <a role="menuitem" lang="ja" >日本語</a> </li> <li role="presentation"> <a role="menuitem" lang="ko" >한국어</a> </li> </ul> </devsite-language-selector> </nav> </div> </devsite-footer-utility> <devsite-panel></devsite-panel> </section></section> <devsite-sitemask></devsite-sitemask> <devsite-snackbar></devsite-snackbar> <devsite-tooltip ></devsite-tooltip> <devsite-heading-link></devsite-heading-link> <devsite-analytics> <script type="application/json" analytics>[{"dimensions": {"dimension2": false, "dimension5": false, "dimension4": "en", "dimension1": "Signed out", "dimension3": "en"}, "gaid": "UA-61082125-3", "metrics": {}, "purpose": 0}]</script> <script type="application/json" tag-management>{"at": "True", "ga4": [{"id": "G-GBZW986TQ3", "purpose": 0}], "ga4p": [{"id": "G-GBZW986TQ3", "purpose": 0}], "gtm": [], "parameters": {"internalUser": "False", "language": {"machineTranslated": "False", "requested": "en", "served": "en"}, "pageType": "article", "projectName": "Bazel", "signedIn": "False", "tenant": "bazel", "recommendations": {"sourcePage": "", "sourceType": 0, "sourceRank": 0, "sourceIdenticalDescriptions": 0, "sourceTitleWords": 0, "sourceDescriptionWords": 0, "experiment": ""}, "experiment": {"ids": ""}}}</script> </devsite-analytics> <devsite-badger></devsite-badger> <script nonce="4ssoHqf/UUrUe7zZeDJWYaa39wKAL2"> (function(d,e,v,s,i,t,E){d['GoogleDevelopersObject']=i; t=e.createElement(v);t.async=1;t.src=s;E=e.getElementsByTagName(v)[0]; E.parentNode.insertBefore(t,E);})(window, document, 'script', 'https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel/js/app_loader.js', '[40,"en",null,"/js/devsite_app_module.js","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel","https://bazel-dot-devsite-v2-prod-3p.appspot.com",null,null,["/_pwa/bazel/manifest.json","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/images/video-placeholder.svg","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel/images/favicon-prod.png","https://www.gstatic.com/devrel-devsite/prod/v870e399c64f7c43c99a3043db4b3a74327bb93d0914e84a0c3dba90bbfd67625/bazel/images/lockup.svg","https://fonts.googleapis.com/css?family=Roboto:300,400,400italic,500,500italic,700,700italic|Roboto+Mono:400,500,700&display=swap"],1,null,[1,6,8,12,14,17,21,25,50,52,63,70,75,76,80,87,91,92,93,97,98,100,101,102,103,104,105,107,108,109,110,112,113,116,117,118,120,122,124,125,126,127,129,130,131,132,133,134,135,136,138,140,141,147,148,149,151,152,156,157,158,159,161,163,164,168,169,170,179,180,182,183,186,191,193,196],"AIzaSyCNm9YxQumEXwGJgTDjxoxXK6m1F-9720Q","AIzaSyCc76DZePGtoyUjqKrLdsMGk_ry7sljLbY","bazel.build","AIzaSyB9bqgQ2t11WJsOX8qNsCQ6U-w91mmqF-I","AIzaSyAdYnStPdzjcJJtQ0mvIaeaMKj7_t6J_Fg",null,null,null,["Cloud__enable_llm_concierge_chat","SignIn__enable_refresh_access_tokens","Profiles__enable_release_notes_notifications","TpcFeatures__enable_mirror_tenant_redirects","Profiles__require_profile_eligibility_for_signin","MiscFeatureFlags__enable_variable_operator","BookNav__enable_tenant_cache_key","Concierge__enable_pushui","Cloud__enable_cloudx_ping","Profiles__enable_profile_collections","Profiles__enable_developer_profiles_callout","MiscFeatureFlags__enable_view_transitions","Experiments__reqs_query_experiments","Search__enable_page_map","MiscFeatureFlags__enable_explain_this_code","OnSwitch__enable","Profiles__enable_complete_playlist_endpoint","DevPro__enable_cloud_innovators_plus","SignIn__enable_oauth_multi_account_support","Profiles__enable_awarding_url","Profiles__enable_dashboard_curated_recommendations","EngEduTelemetry__enable_engedu_telemetry","Cloud__enable_cloud_shell","Profiles__enable_public_developer_profiles","Profiles__enable_recognition_badges","MiscFeatureFlags__developers_footer_dark_image","Cloud__enable_free_trial_server_call","Cloud__enable_cloud_shell_fte_user_flow","CloudShell__cloud_shell_button","Search__enable_suggestions_from_borg","DevPro__enable_developer_subscriptions","Analytics__enable_clearcut_logging","Profiles__enable_page_saving","Cloud__enable_cloudx_experiment_ids","Search__enable_dynamic_content_confidential_banner","Search__enable_ai_eligibility_checks","Cloud__enable_cloud_facet_chat","CloudShell__cloud_code_overflow_menu","Profiles__enable_completecodelab_endpoint","MiscFeatureFlags__developers_footer_image","MiscFeatureFlags__enable_project_variables","Cloud__enable_legacy_calculator_redirect","Cloud__enable_cloud_dlp_service","MiscFeatureFlags__enable_firebase_utm","MiscFeatureFlags__emergency_css","TpcFeatures__enable_required_headers","SignIn__enable_auto_login_multi_account"],null,null,"AIzaSyA58TaKli1DculwmAmbpzLVGuWc8eCQgQc","https://developerscontentserving-pa.googleapis.com","AIzaSyDWBU60w0P9hEkr29kkksYs8Z7gvZ8u_wc","https://developerscontentsearch-pa.googleapis.com",2,4,null,"https://developerprofiles-pa.googleapis.com",[40,"bazel","Bazel","bazel.build",null,"bazel-dot-devsite-v2-prod-3p.appspot.com",null,null,[null,1,null,null,null,null,null,null,null,null,null,[1],null,null,null,null,null,null,[1],null,null,null,null,[1,1,1],[1,1,null,1,1]],null,[56,null,null,null,null,null,"/images/lockup.svg",null,null,null,null,1,null,null,null,null,null,null,null,null,null,1,null,null,null,null,[]],[],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[6,7,1,18,20,22,23,29,37,39,40,43],null,[[],[1,1]],[[["UA-61082125-3"],["UA-61082125-4"],null,null,["UA-61082125-5"],null,null,[["G-GBZW986TQ3"],null,null,[["G-GBZW986TQ3",1]]],[["UA-61082125-3",1]],null,[["UA-61082125-5",1]],null,1],[[3,4],[5,8],[4,5],[1,1],[2,2]]],null,4]]') </script> <devsite-a11y-announce></devsite-a11y-announce> </body> </html>