Es una especificación exhaustiva del entorno de ejecución de pruebas.
Información general
El lenguaje de COMPILACIÓN de Bazel incluye reglas que se pueden usar para definir programas de prueba automatizados en muchos lenguajes.
Las pruebas se ejecutan con bazel test
.
Los usuarios también pueden ejecutar objetos binarios de prueba directamente. Esto se permite, pero no se respalda, ya que tal invocación no cumplirá con los mandatos que se describen a continuación.
Las pruebas deben ser herméticas, es decir, deben acceder solo a los recursos en los que tienen una dependencia declarada. Si las pruebas no son debidamente herméticas, no proporcionan resultados históricamente reproducibles. Esto podría ser un problema significativo para el hallazgo culpable (determinar qué cambio rompió una prueba), la auditabilidad de ingeniería de lanzamiento y el aislamiento de recursos de las pruebas (los frameworks de prueba automatizados no deben generar DDoS en un servidor porque algunas pruebas se comunican con él).
Objetivo
El objetivo de esta página es establecer de manera formal el entorno de ejecución y el comportamiento esperado de las pruebas de Bazel. También impone requisitos al ejecutor de pruebas y al sistema de compilación.
La especificación del entorno de pruebas ayuda a los autores de pruebas a evitar depender de comportamientos no especificados y, por lo tanto, brinda a la infraestructura de pruebas más libertad para realizar cambios de implementación. La especificación reduce algunos agujeros que en la actualidad permiten que se aprueben muchas pruebas a pesar de no ser debidamente hermética, determinista y reentrante.
El objetivo de esta página es ser normativa y autoritativa. Si esta especificación y el comportamiento implementado del ejecutor de pruebas no coinciden, la especificación tiene prioridad.
Especificación propuesta
Las palabras clave “DEBE”, “NO DEBE”, “OBLIGATORIO”, “DEBERÁ”, “NO DEBERÍA”, “DEBERÍA”, “NO DEBERÍA”, “RECOMENDADO”, “PUEDE” y “OPCIONAL” deben interpretarse como se describe en IETF RFC 2119.
Propósito de las pruebas
El propósito de las pruebas de Bazel es confirmar algunas propiedades de los archivos de origen registrados en el repositorio. (En esta página, los “archivos de origen” incluyen datos de prueba, resultados dorados y cualquier otro elemento que se mantenga bajo el control de versión). Un usuario escribe una prueba para confirmar una invariante que espera que se mantenga. Otros usuarios ejecutan la prueba más tarde para verificar si la variante está dañada. Si la prueba depende de variables que no sean archivos de origen (no herméticos), su valor se reduce, ya que los usuarios posteriores no pueden estar seguros de que los cambios son erróneos cuando la prueba deja de pasar.
Por lo tanto, el resultado de una prueba debe depender únicamente de lo siguiente:
- archivos fuente en los que la prueba tiene una dependencia declarada
- productos del sistema de compilación en los que la prueba tiene una dependencia declarada
- recursos cuyo comportamiento está garantizado por el ejecutor de pruebas para permanecer constantes
Actualmente, no se aplica de manera forzosa ese comportamiento. Sin embargo, los ejecutores de pruebas se reservan el derecho de agregar tal aplicación en el futuro.
Rol del sistema de compilación
Las reglas de prueba son similares a las reglas binarias, ya que cada una debe generar un programa ejecutable. Para algunos lenguajes, este es un programa de stub que combina un agente específico de lenguaje con el código de prueba. Las reglas de prueba también deben producir otros resultados. Además del ejecutable de prueba principal, el ejecutor de pruebas necesitará un manifiesto de runfiles, archivos de entrada que deben estar disponibles para la prueba durante el tiempo de ejecución. Es posible que necesite información sobre el tipo, el tamaño y las etiquetas de una prueba.
El sistema de compilación puede usar los archivos de ejecución para entregar código y datos. (Esto se puede usar a modo de optimización para reducir el tamaño de cada objeto binario de prueba compartiendo archivos entre las pruebas, por ejemplo, mediante el uso de vínculos dinámicos). El sistema de compilación debe asegurarse de que el ejecutable generado cargue estos archivos mediante la imagen de archivos de ejecución proporcionada por el ejecutor de pruebas, en lugar de referencias codificadas a ubicaciones absolutas en el árbol de fuente o resultado.
Función del ejecutor de pruebas
Desde el punto de vista del ejecutor de pruebas, cada prueba es un programa que se puede invocar con execve()
. Puede haber otras formas de ejecutar pruebas. Por ejemplo, un IDE puede permitir la ejecución de pruebas de Java en el proceso. Sin embargo, el resultado de ejecutar la prueba como un proceso independiente debe considerarse autorizado. Si un proceso de prueba se ejecuta hasta completarse y termina normalmente con un código de salida de cero, significa que la prueba fue exitosa. Cualquier otro resultado se considera una prueba fallida. En particular, escribir cualquiera de las strings PASS
o FAIL
en stdout no tiene importancia para el ejecutor de pruebas.
Si una prueba tarda demasiado en ejecutarse, excede algún límite de recursos o el ejecutor de pruebas detecta un comportamiento prohibido, puede optar por finalizar la prueba y tratar la ejecución como un error. El ejecutor no debe informar que la prueba fue aprobada después de enviar una señal al proceso de prueba o a sus elementos secundarios.
Se otorga un tiempo limitado para completarse a todo el objetivo de prueba (no a métodos ni pruebas individuales). El límite de tiempo de una prueba se basa en su atributo timeout
de acuerdo con la siguiente tabla:
tiempo de espera | Límite de tiempo (s) |
---|---|
short | 60 |
Moderada | 300 |
long | 900 |
eterno | 3,600 |
Las pruebas que no especifican un tiempo de espera de forma explícita tienen uno implícito basado en el size
de la prueba de la siguiente manera:
size | Etiqueta de tiempo de espera implícita |
---|---|
poco a poco | short |
medium | Moderada |
grandes | long |
enorme | eterno |
Si se trata de una prueba “grande” sin una configuración de tiempo de espera explícita, se asignarán 900 segundos para ejecutarse. A una prueba "media" con un tiempo de espera "corto" se le asignarán 60 segundos.
A diferencia de timeout
, size
también determina el uso máximo previsto de otros recursos (como la RAM) cuando se ejecuta la prueba de forma local, como se describe en Definiciones comunes.
Todas las combinaciones de etiquetas size
y timeout
son legales, por lo que se puede declarar una prueba "enorme" con un tiempo de espera "corto". Es probable que haga algunas cosas
horriblemente muy rápido.
Las pruebas pueden ser arbitrariamente rápidas, sin importar el tiempo de espera. Una prueba no recibe penalizaciones por un tiempo de espera excesivamente generoso, aunque se puede emitir una advertencia: por lo general, debes establecer el tiempo de espera lo más estricto posible, sin inconsistencias.
El tiempo de espera de la prueba se puede anular con la marca de bazel --test_timeout
cuando
se ejecuta de forma manual en condiciones que se sabe que son lentas. Los valores --test_timeout
están en segundos. Por ejemplo, --test_timeout=120
establece el tiempo de espera de la prueba en dos minutos.
También existe un límite inferior recomendado para los tiempos de espera de las pruebas de la siguiente manera:
tiempo de espera | Tiempo mínimo (s) |
---|---|
short | 0 |
Moderada | 30 |
long | 300 |
eterno | 900 |
Por ejemplo, si una prueba "moderada" se completa en 5.5 s, considera configurar timeout =
"short"
o size = "small"
. Con la opción de línea de comandos --test_verbose_timeout_warnings
de
bazel, se mostrarán las pruebas cuyo tamaño especificado es demasiado grande.
Los tamaños de las pruebas y los tiempos de espera se especifican en el archivo BUILD según la especificación aquí. Si no se especifica, el tamaño de una prueba se establecerá de forma predeterminada en “mediano”.
Si el proceso principal de una prueba finaliza, pero algunos de sus elementos secundarios aún se están ejecutando, el ejecutor de pruebas debe considerar que la ejecución está completa y contarla como un éxito o un fracaso en función del código de salida observado en el proceso principal. El ejecutor de pruebas puede finalizar cualquier proceso desviado. Las pruebas no deben filtrar procesos de esta manera.
Fragmentación de pruebas
Las pruebas se pueden paralelizar mediante la fragmentación de pruebas. Consulta --test_sharding_strategy
y shard_count
para habilitar la fragmentación de pruebas. Cuando se habilita la fragmentación, el ejecutor de pruebas se inicia una vez por fragmento. La variable de entorno TEST_TOTAL_SHARDS
es la cantidad de fragmentos y TEST_SHARD_INDEX
es el índice de fragmentos, que comienza en 0. Los ejecutores usan esta información para seleccionar qué pruebas
ejecutar; por ejemplo, mediante una estrategia de round-robin. No todos los ejecutores de pruebas admiten la fragmentación. Si un ejecutor admite la fragmentación, debe crear o actualizar la fecha de la última modificación del archivo que especifica TEST_SHARD_STATUS_FILE
. De lo contrario, Bazel supone que no admite la fragmentación y que no iniciará ejecutores adicionales.
Condiciones iniciales
Cuando se ejecuta una prueba, el ejecutor de pruebas debe establecer ciertas condiciones iniciales.
El ejecutor de pruebas debe invocar cada prueba con la ruta de acceso al ejecutable de la prueba en argv[0]
. Esta ruta de acceso debe ser relativa y estar debajo del directorio actual de la prueba (que se encuentra en el árbol de archivos de ejecución, como se muestra a continuación). El ejecutor de pruebas no debe pasar ningún otro argumento a una prueba, a menos que el usuario lo solicite de manera explícita.
El bloque de entorno inicial debe estar compuesto por lo siguiente:
Variable | Valor | Estado |
---|---|---|
HOME |
valor de $TEST_TMPDIR |
recomendado |
LANG |
unset | obligatorio |
LANGUAGE |
unset | obligatorio |
LC_ALL |
unset | obligatorio |
LC_COLLATE |
unset | obligatorio |
LC_CTYPE |
unset | obligatorio |
LC_MESSAGES |
unset | obligatorio |
LC_MONETARY |
unset | obligatorio |
LC_NUMERIC |
unset | obligatorio |
LC_TIME |
unset | obligatorio |
LD_LIBRARY_PATH |
lista de directorios separados por dos puntos que contienen bibliotecas compartidas | opcional |
JAVA_RUNFILES |
valor de $TEST_SRCDIR |
en desuso |
LOGNAME |
valor de $USER |
obligatorio |
PATH |
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:. |
recomendado |
PWD |
$TEST_SRCDIR/workspace-name |
recomendado |
SHLVL |
2 |
recomendado |
TEST_INFRASTRUCTURE_FAILURE_FILE |
ruta de acceso absoluta a un archivo privado en un directorio que admite escritura (este archivo solo se debe usar para informar fallas que se originan en la infraestructura de pruebas, no como un mecanismo general para informar fallas inestables de las pruebas. En este contexto, la infraestructura de pruebas se define como sistemas o bibliotecas que no son específicos de una prueba, pero que pueden causar fallas de prueba debido a un mal funcionamiento. La primera línea es el nombre del componente de la infraestructura de pruebas que causó la falla, y la segunda, una descripción legible de la falla. Se ignoran las líneas adicionales). | opcional |
TEST_LOGSPLITTER_OUTPUT_FILE |
ruta de acceso absoluta a un archivo privado en un directorio de escritura (se usa para escribir el registro de protobuffer de Logsplitter) | opcional |
TEST_PREMATURE_EXIT_FILE |
ruta de acceso absoluta a un archivo privado en un directorio que admite escritura (se usa para capturar llamadas a exit() ) |
opcional |
TEST_RANDOM_SEED |
Si se usa la opción --runs_per_test , TEST_RANDOM_SEED se establece en run number (comienza con 1) para cada ejecución de prueba individual. |
opcional |
TEST_RUN_NUMBER |
Si se usa la opción --runs_per_test , TEST_RUN_NUMBER se establece en run number (comienza con 1) para cada ejecución de prueba individual. |
opcional |
TEST_TARGET |
El nombre del destino que se está probando | opcional |
TEST_SIZE |
La prueba size |
opcional |
TEST_TIMEOUT |
La prueba timeout en segundos |
opcional |
TEST_SHARD_INDEX |
índice de fragmento, si se usa sharding |
opcional |
TEST_SHARD_STATUS_FILE |
ruta de acceso al archivo que se debe tocar para indicar la compatibilidad con sharding |
opcional |
TEST_SRCDIR |
ruta de acceso absoluta a la base del árbol de archivos de ejecución | obligatorio |
TEST_TOTAL_SHARDS |
shard count en total, si se usa sharding |
opcional |
TEST_TMPDIR |
ruta de acceso absoluta a un directorio privado que admite escritura | obligatorio |
TEST_WORKSPACE |
nombre del lugar de trabajo del repositorio local | opcional |
TEST_UNDECLARED_OUTPUTS_DIR |
ruta de acceso absoluta a un directorio privado que admite escritura (se usa para escribir resultados de prueba no declarados) | opcional |
TEST_UNDECLARED_OUTPUTS_ANNOTATIONS_DIR |
ruta de acceso absoluta a un directorio privado que admite escritura (se usa para escribir archivos .part y .pb de anotaciones de resultados de prueba no declarados). |
opcional |
TEST_WARNINGS_OUTPUT_FILE |
ruta de acceso absoluta a un archivo privado en un directorio de escritura (se usa para escribir advertencias de destino de prueba) | opcional |
TESTBRIDGE_TEST_ONLY |
valor de --test_filter , si se especifica |
opcional |
TZ |
UTC |
obligatorio |
USER |
valor de getpwuid(getuid())->pw_name |
obligatorio |
XML_OUTPUT_FILE |
Es la ubicación en la que las acciones de prueba deben escribir un archivo de salida XML del resultado de la prueba. De lo contrario, Bazel genera un archivo de salida XML predeterminado que une el registro de pruebas como parte de la acción de prueba. El esquema XML se basa en el esquema de resultados de la prueba JUnit. | opcional |
BAZEL_TEST |
Indica que bazel test controla el ejecutable de prueba |
obligatorio |
El entorno puede contener entradas adicionales. Las pruebas no deben depender de la presencia, ausencia ni el valor de ninguna variable de entorno que no se haya mencionado anteriormente.
El directorio de trabajo inicial será $TEST_SRCDIR/$TEST_WORKSPACE
.
El ID del proceso actual, el ID de grupo de procesos, el ID de sesión y el ID de proceso superior no se especifican. El proceso puede o no ser un líder de grupo de procesos o un líder de sesión. El proceso puede o no tener una terminal de control. El proceso puede tener cero o más procesos secundarios en ejecución o no recolectados. El proceso no debe tener varios subprocesos cuando el código de prueba obtiene el control.
El descriptor de archivo 0 (stdin
) debe estar abierto para la lectura, pero no se especifica a qué se adjunta. Las pruebas no deben leerla. Los descriptores de archivo 1 (stdout
) y 2 (stderr
) deben estar disponibles para su escritura, pero no se especifica a qué se adjuntan. Podría ser una terminal, una canalización, un archivo regular o cualquier otra cosa en la que se puedan escribir caracteres. Pueden compartir una entrada en la tabla de archivos abiertos (es decir, no pueden buscar de forma independiente). Las pruebas no deben heredar ningún otro descriptor de archivo abierto.
La máscara inicial será 022
o 027
.
No deberá quedar pendiente ningún temporizador de intervalo o alarma.
La máscara inicial de las señales bloqueadas debe estar vacía. Todas las señales deben tener la acción predeterminada.
Los límites iniciales de recursos, tanto flexibles como estrictos, deben definirse de la siguiente manera:
Recurso | Límite |
---|---|
RLIMIT_AS |
unlimited |
RLIMIT_CORE |
sin especificar |
RLIMIT_CPU |
unlimited |
RLIMIT_DATA |
unlimited |
RLIMIT_FSIZE |
unlimited |
RLIMIT_LOCKS |
unlimited |
RLIMIT_MEMLOCK |
unlimited |
RLIMIT_MSGQUEUE |
sin especificar |
RLIMIT_NICE |
sin especificar |
RLIMIT_NOFILE |
al menos 1,024 |
RLIMIT_NPROC |
sin especificar |
RLIMIT_RSS |
unlimited |
RLIMIT_RTPRIO |
sin especificar |
RLIMIT_SIGPENDING |
sin especificar |
RLIMIT_STACK |
ilimitado, o 2,044 KB <= rlim <= 8,192 KB |
No se especifican los tiempos de proceso iniciales (como los muestra times()
) y el uso de recursos (como los muestra getrusage()
).
No se especifican la política de programación inicial ni la prioridad.
Función del sistema host
Además de los aspectos del contexto del usuario bajo control directo del ejecutor de pruebas, el sistema operativo en el que se ejecutan las pruebas debe satisfacer ciertas propiedades para que una ejecución de prueba sea válida.
Sistema de archivos
El directorio raíz que observa una prueba puede o no ser el directorio raíz real.
Se debe activar /proc
.
Todas las herramientas de compilación deberán estar presentes en las rutas de acceso absolutas en /usr
que usa una instalación local.
Es posible que las rutas que comiencen con /home
no estén disponibles. Las pruebas no deben acceder a ninguna de esas rutas.
/tmp
debe admitir la escritura, pero las pruebas deben evitar el uso de estas rutas de acceso.
Las pruebas no deben suponer que hay una ruta de acceso constante disponible para su uso exclusivo.
Las pruebas no deben suponer que las atimes están habilitadas para cualquier sistema de archivos activado.
Usuarios y grupos
Los usuarios raíz, nadie y unittest deben existir. La raíz del grupo, eng y nadie deben existir.
Las pruebas se deben ejecutar como un usuario no raíz. Los ID de usuario reales y efectivos deben ser iguales, del mismo modo para los ID de grupo. Además, no se especifican el ID de usuario, el ID de grupo, el nombre de usuario y el nombre de grupo actuales. No se especifica el conjunto de IDs de grupo complementarios.
El ID de usuario y el ID de grupo actuales deben tener los nombres correspondientes que se puedan recuperar con getpwuid()
y getgrgid()
. Es posible que no suceda lo mismo con los IDs de grupo complementarios.
El usuario actual debe tener un directorio principal. Es posible que no tenga escritura. Las pruebas no deben intentar escribir en él.
Herramientas de redes
No se especificó el nombre de host. Puede contener un punto o no. Resolver el nombre de host debe proporcionar una dirección IP del host actual. La resolución del corte del nombre de host después del primer punto también debe funcionar. Debe resolverse el nombre de host localhost.
Otros recursos
A las pruebas se les otorga al menos un núcleo de CPU. Es posible que haya otros, pero no está garantizado. No se especifican otros aspectos de rendimiento de este núcleo. Puedes aumentar la reserva a una mayor cantidad de núcleos de CPU si agregas la etiqueta “cpu:n” (donde n es un número positivo) a una regla de prueba. Si una máquina tiene menos núcleos de CPU totales que los solicitados, Bazel ejecutará la prueba de todos modos. Si una prueba usa la fragmentación, cada fragmento individual reservará la cantidad de núcleos de CPU que se especifica aquí.
Las pruebas pueden crear subprocesos, pero no procesar grupos ni sesiones.
Existe un límite para la cantidad de archivos de entrada que puede consumir una prueba. Este límite está sujeto a cambios, pero actualmente se encuentra en el rango de decenas de miles de entradas.
Hora y fecha
La hora y la fecha actuales no se especifican. La zona horaria del sistema no está especificada.
X Las ventanas pueden o no estar disponibles. Las pruebas que necesitan un servidor X deben iniciar Xvfb.
Prueba la interacción con el sistema de archivos
Todas las rutas de acceso a archivos especificadas en las variables de entorno de pruebas apuntan a algún lugar del sistema de archivos local, a menos que se especifique lo contrario.
Las pruebas deben crear archivos solo dentro de los directorios especificados por $TEST_TMPDIR
y $TEST_UNDECLARED_OUTPUTS_DIR
(si están configurados).
Inicialmente, estos directorios estarán vacíos.
Las pruebas no deben intentar quitar, modificar ni modificar de otra manera estos directorios.
Estos directorios pueden ser vínculos simbólicos.
El tipo de sistema de archivos de $TEST_TMPDIR/.
permanece sin especificar.
Las pruebas también pueden escribir archivos .part en $TEST_UNDECLARED_OUTPUTS_ANNOTATIONS_DIR
para anotar archivos de salida no declarados.
En casos excepcionales, es posible que una prueba cree archivos en /tmp
de manera forzosa. Por ejemplo, los límites de longitud de ruta de acceso para sockets de dominio Unix suelen requerir la creación del socket en /tmp
. Bazel no podrá
realizar un seguimiento de esos archivos. La prueba en sí debe asegurarse de ser hermética, de usar rutas de acceso
únicas para evitar colisionar con otras que ejecutan pruebas y procesos no
de prueba de forma simultánea, y limpiar los archivos que crea en /tmp
.
Algunos frameworks de prueba populares, como JUnit4 TemporaryFolder
o Go TempDir
, tienen sus propias formas de crear un directorio temporal en /tmp
. Estos frameworks de prueba incluyen una funcionalidad que borra los archivos de /tmp
, por lo que puedes usarlos aunque creen archivos fuera de TEST_TMPDIR
.
Las pruebas deben acceder a las entradas a través del mecanismo runfiles o cualquier otra parte del entorno de ejecución que estén diseñadas específicamente para que los archivos de entrada estén disponibles.
Las pruebas no deben acceder a otras salidas del sistema de compilación en rutas de acceso inferidas a partir de la ubicación de su propio archivo ejecutable.
No se especifica si el árbol de archivos de ejecución contiene archivos normales, vínculos simbólicos o una mezcla. El árbol de archivos de ejecución puede contener symlinks a directorios.
En las pruebas, se deben evitar el uso de rutas de acceso que contengan componentes ..
dentro del árbol de archivos de ejecución.
No se debe poder escribir en ningún directorio, archivo ni symlink dentro del árbol de archivos de ejecución (incluidas las rutas que
desvían symlinks). (Deduce que no se pueda escribir en el directorio de trabajo inicial). En las pruebas, no se debe suponer que se puede escribir en alguna parte de los archivos de ejecución ni que es propiedad del usuario actual (por ejemplo, chmod
y chgrp
pueden fallar).
El árbol de archivos de ejecución (incluidas las rutas de acceso que recorren symlinks) no debe cambiar durante la ejecución de la prueba. Los directorios superiores y las activaciones del sistema de archivos no deben cambiar de ninguna manera que afecte el resultado de resolver una ruta de acceso dentro del árbol de archivos de ejecución.
Para detectar una salida temprana, una prueba puede crear un archivo en la ruta de acceso especificada por TEST_PREMATURE_EXIT_FILE
al inicio y quitarlo al salir. Si Bazel ve el
archivo cuando finaliza la prueba, supondrá que la prueba se cerró de forma prematura y
lo marcará como fallida.
Convenciones de etiquetas
Algunas etiquetas tienen un significado especial en las reglas de prueba. Consulta también la enciclopedia de compilación de Bazel en el atributo tags
.
Etiqueta | Significado |
---|---|
exclusive |
no ejecutar ninguna otra prueba al mismo tiempo |
external |
la prueba tiene una dependencia externa; inhabilita el almacenamiento en caché de la prueba. |
large |
Convención test_suite ; paquete de pruebas grandes |
manual * |
No incluyas el destino de prueba en patrones de destino comodín, como :... , :* o :all . |
medium |
Convención test_suite ; conjunto de pruebas de nivel intermedio |
small |
Convención test_suite ; conjunto de pruebas pequeñas |
smoke |
Convención test_suite , lo que significa que debe ejecutarse antes de confirmar los cambios de código en el sistema de control de versión |
Archivos de ejecución
A continuación, supongamos que hay una regla *_binary() etiquetada
//foo/bar:unittest
, con una dependencia de tiempo de ejecución de la regla etiquetada
//deps/server:server
.
Location
El directorio runfiles de una //foo/bar:unittest
de destino es el directorio $(WORKSPACE)/$(BINDIR)/foo/bar/unittest.runfiles
. Esta ruta se conoce como runfiles_dir
.
Dependencias
El directorio runfiles se declara como una dependencia en tiempo de compilación de la regla *_binary()
. El directorio de runfiles depende del conjunto de archivos de COMPILACIÓN que afectan a la regla *_binary()
o a cualquiera de sus dependencias de tiempo de compilación o ejecución. La modificación de los archivos de origen no afecta la estructura del directorio de runfiles y, por lo tanto, no activa ninguna recompilación.
Contenido
El directorio runfiles contiene lo siguiente:
- Vínculos simbólicos a dependencias en tiempo de ejecución: Cada OutputFile y CommandRule que es una dependencia de tiempo de ejecución de la regla
*_binary()
se representa con un symlink en el directorio de runfiles. El nombre del symlink es$(WORKSPACE)/package_name/rule_name
. Por ejemplo, el symlink para el servidor se llamaría$(WORKSPACE)/deps/server/server
, y la ruta completa sería$(WORKSPACE)/foo/bar/unittest.runfiles/$(WORKSPACE)/deps/server/server
. El destino del symlink es el OutputFileName() de OutputFile o CommandRule, expresado como una ruta de acceso absoluta. Por lo tanto, el destino del symlink puede ser$(WORKSPACE)/linux-dbg/deps/server/42/server
. - Vínculos simbólicos a subarchivos de ejecución: Por cada
*_binary()
Z que es una dependencia del tiempo de ejecución de*_binary()
C, hay un segundo vínculo en el directorio de archivos de ejecución de C a los archivos de ejecución de Z. El nombre del symlink es$(WORKSPACE)/package_name/rule_name.runfiles
. El destino del symlink es el directorio de runfiles. Por ejemplo, todos los subprogramas comparten un directorio de archivos de ejecución común.