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 &nbsp;|&nbsp; Bazel</title> <meta property="og:title" content="Rules Tutorial &nbsp;|&nbsp; 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&#39;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&#39;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 &quot;Build Language&quot;, though it is often simply referred to as &quot;Starlark&quot;, especially when emphasizing that a feature is expressed in the Build Language as opposed to being a built-in or &quot;native&quot; 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(&#34;:foo.bzl&#34;, &#34;foo_binary&#34;) foo_binary(name = &#34;bin&#34;) </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&#39;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(&#34;analyzing&#34;, ctx.label) foo_binary = rule( implementation = _foo_binary_impl, ) print(&#34;bzl file evaluation&#34;) </code></pre> <p>and BUILD:</p> <pre class="prettyprint lang-python" translate="no" dir="ltr"><code translate="no" dir="ltr">load(&#34;:foo.bzl&#34;, &#34;foo_binary&#34;) print(&#34;BUILD file&#34;) foo_binary(name = &#34;bin1&#34;) foo_binary(name = &#34;bin2&#34;) </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>&quot;bzl file evaluation&quot; 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 &quot;bzl file evaluation&quot; 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&#39;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> (&quot;configured query&quot;) 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 &quot;bzl file evaluation&quot; nor &quot;BUILD file&quot; 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 = &#34;Hello\n&#34;, ) </code></pre> <p>The code is valid, but it won&#39;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&#39;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 = &#34;Hello!\n&#34;, ) 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 = { &#34;username&#34;: 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 = &#34;bin&#34;, username = &#34;Alice&#34;, ) </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 = &#34;Hello {}!\n&#34;.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&#39;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">&#34;srcs&#34;: attr.label_list(allow_files = [&#34;.java&#34;]), </code></pre> <p>The list of files can be accessed with <code translate="no" dir="ltr">ctx.files.&lt;attribute name&gt;</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">&#34;src&#34;: attr.label(allow_single_file = [&#34;.java&#34;]) </code></pre> <p>This file is then accessible under <code translate="no" dir="ltr">ctx.file.&lt;attribute name&gt;</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 + &#34;.cc&#34;) ctx.actions.expand_template( output = out, template = ctx.file.template, substitutions = {&#34;{NAME}&#34;: ctx.attr.username}, ) return [DefaultInfo(files = depset([out]))] hello_world = rule( implementation = _hello_world_impl, attrs = { &#34;username&#34;: attr.string(default = &#34;unknown person&#34;), &#34;template&#34;: attr.label( allow_single_file = [&#34;.cc.tpl&#34;], 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 = &#34;hello&#34;, username = &#34;Alice&#34;, template = &#34;file.cc.tpl&#34;, ) cc_binary( name = &#34;hello_bin&#34;, srcs = [&#34;:hello&#34;], ) </code></pre> <p>If you don&#39;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"> &#34;_template&#34;: attr.label( allow_single_file = True, default = &#34;file.cc.tpl&#34;, ), </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&#39;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([&#34;file.cc.tpl&#34;]) </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>[{&#34;dimensions&#34;: {&#34;dimension2&#34;: false, &#34;dimension5&#34;: false, &#34;dimension4&#34;: &#34;en&#34;, &#34;dimension1&#34;: &#34;Signed out&#34;, &#34;dimension3&#34;: &#34;en&#34;}, &#34;gaid&#34;: &#34;UA-61082125-3&#34;, &#34;metrics&#34;: {}, &#34;purpose&#34;: 0}]</script> <script type="application/json" tag-management>{&#34;at&#34;: &#34;True&#34;, &#34;ga4&#34;: [{&#34;id&#34;: &#34;G-GBZW986TQ3&#34;, &#34;purpose&#34;: 0}], &#34;ga4p&#34;: [{&#34;id&#34;: &#34;G-GBZW986TQ3&#34;, &#34;purpose&#34;: 0}], &#34;gtm&#34;: [], &#34;parameters&#34;: {&#34;internalUser&#34;: &#34;False&#34;, &#34;language&#34;: {&#34;machineTranslated&#34;: &#34;False&#34;, &#34;requested&#34;: &#34;en&#34;, &#34;served&#34;: &#34;en&#34;}, &#34;pageType&#34;: &#34;article&#34;, &#34;projectName&#34;: &#34;Bazel&#34;, &#34;signedIn&#34;: &#34;False&#34;, &#34;tenant&#34;: &#34;bazel&#34;, &#34;recommendations&#34;: {&#34;sourcePage&#34;: &#34;&#34;, &#34;sourceType&#34;: 0, &#34;sourceRank&#34;: 0, &#34;sourceIdenticalDescriptions&#34;: 0, &#34;sourceTitleWords&#34;: 0, &#34;sourceDescriptionWords&#34;: 0, &#34;experiment&#34;: &#34;&#34;}, &#34;experiment&#34;: {&#34;ids&#34;: &#34;&#34;}}}</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>

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