blob: 1579bf78d9d25fe96602f567e6148573f34d0d1c [file] [log] [blame]
{namespace buck.macros}
/***/
{template .soyweb}
{call buck.page}
{param title: 'Macros' /}
{param prettify: true /}
{param content}
Because build files accept valid Python code, it is possible to define
Python functions that have the side-effect of creating build rules.
Such functions are called <strong>macros</strong>.
<p>
<strong>Warning:</strong> Although build files are evaluated as Python
and can therefore do anything (write files, access the network, etc.),
doing so may cause Buck to fail in peculiar ways and is therefore neither
supported nor encouraged.
<p>
For example, here is a macro named <code>java_library_using_guava</code> to
create a build rule that creates a <code>java_library</code> rule that depends
on Guava:
{literal}<pre class="prettyprint lang-py">
def java_library_using_guava(
name,
srcs=[],
resources=[],
deps=[],
visibility=[]):
java_library(
name = name,
srcs = srcs,
resources = resources,
deps = [
# This assumes this is where Guava is in your project.
'//third_party/java/guava:guava',
] + deps,
visibility = visibility,
)
</pre>{/literal}
Calling this function looks the same as defining a built-in build rule:
{literal}<pre class="prettyprint lang-py">
# Calling this function has the side-effect of creating
# a java_library() rule named 'util' that depends on Guava.
java_library_using_guava(
name = 'util',
# Source code that depends on Guava.
srcs = glob(['*.java']),
)
</pre>{/literal}
You can also create more sophisticated macros that create multiple build
rules. For example, you might want to create a single build rule that
produces both debug and release versions of an APK:
{literal}<pre class="prettyprint lang-py">
def create_apks(
name,
manifest,
debug_keystore,
release_keystore,
proguard_config,
deps):
# This loop will create two android_binary rules.
for type in [ 'debug', 'release' ]:
# Select the appropriate keystore.
if type == 'debug':
keystore = debug_keystore
else:
keystore = release_keystore
android_binary(
# Note how we must parameterize the name of the
# build rule so that we avoid creating two build
# rules with the same name.
name = '%s_%s' % (name, type),
manifest = manifest,
target = 'Google Inc.:Google APIs:16',
keystore = keystore,
package_type = type,
proguard_config = proguard_config,
deps = deps,
visibility = [
'PUBLIC',
],
)
)
</pre>{/literal}
Again, using this looks the same as defining a built-in build rule:
{literal}<pre class="prettyprint lang-py">
create_apks(
name = 'messenger',
manifest = 'AndroidManifest.xml',
debug_keystore = '//keystores:debug',
release_keystore = '//keystores:prod',
proguard_config = 'proguard.cfg',
deps = [
# ...
],
)
{/literal}</pre>
Note that if this were defined in <code>apps/messenger/BUCK</code>,
then this would create the following build rules:
{literal}<pre>
//apps/messenger:messenger_debug
//apps/messenger:messenger_release
</pre>{/literal}
However, the following build rule would <strong>NOT</strong> exist:
<pre>//apps/messenger:messenger</pre>
This may be confusing to developers who expect the following commands
to work:
{literal}<pre>
buck build //apps/messenger:messenger
buck targets --type create_apks
</pre>{/literal}
Including your company name as a prefix to the name of your macro
may help enforce the idea that your macro is not a built-in rule. On the
other hand, part of the beauty of macros is that they are as familiar
to use as built-in rules. How you communicate this to your team is up
to you.
{/param}
{/call}
{/template}