Idiomas: English | 简体中文 | 繁體中文 | 日本語 | 한국어 | Français | Deutsch | Español | Italiano | Русский | العربية
← ABI de complementos de NeverC
PluginSource.h publica dos tablas. NevercIOAPI es el sistema de archivos:
proveedores de archivos virtuales, lecturas, recorridos de directorios,
sumideros de salida y registro de dependencias. NevercSourceLocationAPI
devuelve las posiciones internas del compilador a archivos, líneas y al texto
tal como está escrito. Entre las dos, un plugin puede servir una cabecera que
solo existe en memoria, resolver una expansión de macro hasta su lugar de
escritura, o escribir una salida lateral que participa en la contabilidad de
durabilidad de la compilación.
#include "neverc/Plugin/PluginSource.h"| Interfaz | Tabla | Macros de versión |
|---|---|---|
NEVERC_INTERFACE_IO_{HIGH,LOW} |
NevercIOAPI |
NEVERC_IO_API_MAJOR / _MINOR |
NEVERC_INTERFACE_SOURCE_LOCATION_{HIGH,LOW} |
NevercSourceLocationAPI |
NEVERC_SOURCE_LOCATION_API_MAJOR / _MINOR |
NEVERC_SOURCE_API_MAJOR y _MINOR son alias del par source-location.
| Fase | Política | Significado |
|---|---|---|
neverc.source.resolve_input |
OBSERVABLE, INTERCEPTABLE | Convertir una entrada del controlador en una entrada de fuente |
neverc.source.open |
además REPLACEABLE | Producir la unidad de fuente de una entrada |
neverc.source.after_open |
OBSERVABLE | Aviso de que una unidad ya está disponible |
Como neverc.source.open es reemplazable, un proveedor puede devolver una
unidad cuyos bytes ha sintetizado él mismo: esa es la manera admitida de
inyectar código generado sin tocar el disco.
Un proveedor VFS reclama un prefijo de ruta y responde a las cuatro preguntas que el compilador hace sobre un archivo.
typedef struct NevercVFSProviderDescriptor {
NevercABITableHeader Header;
NevercStringView ProviderID;
NevercStringView RoutePrefix;
NevercBool Deterministic;
NevercBool Cacheable;
uint64_t Reserved;
NevercVFSPathPredicateFn MatchesPath;
NevercVFSProviderStatusFn Status;
NevercVFSProviderOpenReadFn OpenRead;
NevercVFSProviderReadDirectoryFn ReadDirectory;
NevercVFSProviderCanonicalizeFn Canonicalize;
void *UserData;
NevercDestroyUserDataFn DestroyUserData;
} NevercVFSProviderDescriptor;Cada devolución de llamada rellena un resultado cuyo Disposition indica si el
proveedor atendió la petición:
static NevercStatus NEVERC_CALL
open_read(NevercTaskHandle Task, NevercStringView Path, void *UserData,
NevercVFSOpenReadResult *OutResult) {
static const char Header[] = "#define GENERATED 1\n";
if (!path_matches(Path)) {
OutResult->Disposition = NEVERC_VFS_RESULT_NOT_HANDLED;
return neverc_status_ok();
}
OutResult->Disposition = NEVERC_VFS_RESULT_HANDLED;
OutResult->Status.Type = NEVERC_VFS_FILE_REGULAR;
OutResult->Status.Size = sizeof(Header) - 1;
OutResult->Content.Data = (const uint8_t *)Header;
OutResult->Content.Length = sizeof(Header) - 1;
OutResult->Content.NullTerminated = NEVERC_TRUE;
return neverc_status_ok();
}Devolver NEVERC_VFS_RESULT_NOT_HANDLED pasa al siguiente proveedor y, al
final, al sistema de archivos real. Los tipos de archivo son
NEVERC_VFS_FILE_UNKNOWN, REGULAR, DIRECTORY, SYMLINK y OTHER.
El registro se hace durante Register:
IO->RegisterVFSProvider(IO->Context, RegistrarContext, &Descriptor);Para un único archivo en memoria que solo debe existir durante una sesión, el proveedor sobra:
IO->AddMemoryFile(IO->Context, Session, SV("/virtual/config.h"),
Content, ModificationTime);pluginsdk/examples/VirtualHeaderPlugin.c es un proveedor completo y funcional.
NevercVFSStatus Status;
IO->Stat(IO->Context, Task, Path, &Status);
NevercFileHandle File;
IO->OpenFileForRead(IO->Context, Task, Path, &File);
NevercBufferHandle Buffer;
IO->ReadFile(IO->Context, Task, File, /*Offset=*/0, /*Length=*/Status.Size,
&Buffer);
NevercBufferView View;
IO->GetBufferView(IO->Context, Task, Buffer, &View);
/* View.Data / View.Length / View.NullTerminated */
IO->ReleaseBuffer(IO->Context, Task, Buffer);
IO->CloseFile(IO->Context, Task, File);CopyBuffer convierte bytes de su propiedad en un búfer del anfitrión,
Canonicalize resuelve una ruta, y GetWorkingDirectory /
SetWorkingDirectory manejan el directorio actual de la tarea. Los directorios
se recorren con OpenDirectory, ReadDirectory (que al terminar pone
OutHasEntry a NEVERC_FALSE) y CloseDirectory.
Los códigos de error de E/S se informan en NevercStatus.Detail:
NEVERC_IO_ERROR_NOT_FOUND, PERMISSION_DENIED, NOT_DIRECTORY,
IS_DIRECTORY, INVALID_PATH e IO.
Las salidas son transaccionales. Se abre un sumidero, se escribe y luego se cierra para obtener un sello: un tamaño y un resumen de 32 bytes que el sistema de compilación puede verificar.
NevercOutputSinkHandle Sink;
IO->BeginFileOutput(IO->Context, Task, SV("out.json"), /*SizeBudget=*/0, &Sink);
IO->OutputWrite(IO->Context, Task, Sink, Bytes);
IO->OutputMetadataSet(IO->Context, Task, Sink, SV("content-type"),
SV("application/json"));
NevercOutputSeal Seal = {0};
Seal.Header = (NevercABITableHeader){sizeof(Seal), NEVERC_IO_API_MAJOR,
NEVERC_IO_API_MINOR, 0};
IO->OutputFinish(IO->Context, Task, Sink, &Seal);| Función | Propósito |
|---|---|
BeginMemoryOutput |
Sumidero respaldado por memoria, con nombre lógico |
BeginFileOutput |
Sumidero que aterriza atómicamente en una ruta final |
BeginStreamOutput |
Sumidero sobre NEVERC_OUTPUT_STREAM_STDOUT o _STDERR |
OutputWrite, OutputWriteAt |
Añadir, o escribir en un desplazamiento |
OutputTell, OutputTruncate |
Control de posición y tamaño |
OutputMetadataSet |
Adjuntar un par clave/valor a la salida |
OutputFinish |
Sellar la salida y producir un NevercOutputSeal |
OutputAbort |
Descartar todo lo escrito |
OutputGetSummary |
Inspeccionar estado, banderas, tamaño y resumen en cualquier momento |
NevercOutputSummary.State recorre NEVERC_OUTPUT_OPEN, FINISHED,
COMMITTED, ABORTED o FAILED_PARTIAL, y Flags registra PUBLISHED,
DURABLE, MAY_BE_PARTIAL, RECOVERY_REQUIRED y DURABILITY_UNCONFIRMED.
Esas banderas son la misma información que el controlador expone en
NevercStatus.Flags, de modo que un fallo a mitad de escritura se distingue de
un error limpio.
Un SizeBudget de cero significa sin límite; un presupuesto distinto de cero
hace que un exceso falle con NEVERC_STATUS_RESOURCE_EXHAUSTED en lugar de
llenar un disco.
Si un plugin lee algo que el sistema de compilación debería seguir, dígalo. De lo contrario, una compilación incremental no reconstruirá cuando esa entrada cambie.
NevercDependencyDescriptor Dependency = {0};
Dependency.Header = (NevercABITableHeader){sizeof(Dependency),
NEVERC_IO_API_MAJOR,
NEVERC_IO_API_MINOR, 0};
Dependency.CanonicalPath = SV("/etc/mytool/rules.txt");
Dependency.ContentDigest = Digest;
Dependency.Kind = NEVERC_INPUT_DEPENDENCY_RESOURCE;
Dependency.System = NEVERC_FALSE;
Dependency.ProviderID = SV("com.example.myplugin");
NevercDependencyHandle Handle;
IO->RecordDependency(IO->Context, Task, &Dependency, &Handle);Los tipos son NEVERC_INPUT_DEPENDENCY_SOURCE, INCLUDE, MODULE,
RESOURCE, TOOL y PLUGIN.
Una NevercSourceLocation es opaca. La tabla de ubicaciones la convierte en
algo que se puede imprimir o comparar.
NevercSourceLocationInfo Info = {0};
Info.Header = (NevercABITableHeader){sizeof(Info),
NEVERC_SOURCE_LOCATION_API_MAJOR,
NEVERC_SOURCE_LOCATION_API_MINOR, 0};
Source->GetLocationInfo(Source->Context, Task, Location, &Info);
/* Info.Kind es NEVERC_SOURCE_LOCATION_FILE o _MACRO;
a continuación van Info.FileOffset, Info.Line, Info.Column. */Cuatro transformaciones se mueven entre las vistas de una ubicación, y todas
comparten la firma NevercTransformSourceLocationFn:
| Función | Devuelve |
|---|---|
GetSpellingLocation |
Dónde están escritos realmente los caracteres del token |
GetExpansionLocation |
Dónde aparece la expansión de macro en la fuente |
GetFileLocation |
La ubicación de archivo más cercana |
GetIncludeLocation |
El #include que trajo el archivo |
GetTokenEnd |
Justo después del último carácter del token |
GetPresumedLocation aplica las directivas #line y da un nombre de archivo,
línea, columna y ubicación de inclusión. GetLocationFile junto con
GetFileInfo proporciona la ruta canónica, el tamaño, la fecha de
modificación, el identificador único y si el archivo es de usuario, de sistema
o de sistema extern-C:
typedef struct NevercFileInfo {
NevercABITableHeader Header;
NevercStringView Path;
NevercStringView CanonicalPath;
uint64_t Size;
int64_t ModificationTime;
NevercFileUniqueID UniqueID; /* {Device, File} */
NevercFileCharacteristic Characteristic;
NevercBool NamedPipe;
} NevercFileInfo;Los rangos se leen con GetRangeInfo (que informa de Begin, End y de si el
rango es NEVERC_SOURCE_RANGE_CHARACTER o _TOKEN), y los bytes en sí con
GetSourceText o GetCharacterData.
Cuando se necesitan muchas ubicaciones a la vez —una pasada de diagnóstico sobre una función entera, por ejemplo— use la forma por lotes en lugar de una llamada por ubicación:
Source->GetLocationInfoBatch(Source->Context, Task, Locations, LocationCount,
OutInfos, OutInfoCapacity);La vista de una entrada y sus bytes a nivel de fase:
NevercSourceInputInfo Input = {0};
Source->GetSourceInput(Source->Context, Frame, Frame->Input, &Input);
/* Input.Path, .Kind (FILE o BUFFER), .Language, .System, .Preprocessed */Un proveedor para neverc.source.open responde con una unidad respaldada por
memoria:
NevercMemorySourceUnitDescriptor Unit = {0};
Unit.Header = (NevercABITableHeader){sizeof(Unit),
NEVERC_SOURCE_LOCATION_API_MAJOR,
NEVERC_SOURCE_LOCATION_API_MINOR, 0};
Unit.LogicalPath = SV("/virtual/generated.c");
Unit.CanonicalIdentity = SV("com.example:generated:v1");
Unit.Content = Bytes;
Unit.ProviderID = SV("com.example.myplugin");
Unit.Deterministic = NEVERC_TRUE;
Unit.Cacheable = NEVERC_TRUE;
NevercArtifactHandle Output;
Source->CreateMemorySourceUnit(Source->Context, Frame, Frame->Input, &Unit,
&Output);La caché se indexa por CanonicalIdentity, así que debe cambiar siempre que
cambie el contenido. GetSourceUnit vuelve a leer una unidad e informa además
de MemoryBacked.
- Los búferes de
ReadFile,CopyBufferyPathToBufferpertenecen al anfitrión; libere cada uno conReleaseBuffer. - Cada
OpenFileForReadnecesita unCloseFile; cadaOpenDirectory, unCloseDirectory; cada sumidero de salida, unOutputFinisho unOutputAbort. - Las vistas dentro de
NevercFileInfo,NevercVFSStatusy los resultados de ubicación están prestadas solo durante la devolución de llamada. - La devolución de llamada de un proveedor VFS se ejecuta en el hilo de la tarea y no debe volver a llamar al compilador; responda con los datos que ya tiene.
- Declare
DeterministicyCacheablecon honestidad. Un proveedor que lee el reloj o el entorno y afirma ser determinista producirá una caché de compilación envenenada. AddMemoryFiletiene alcance de sesión; cuando el contenido depende de la tarea, el proveedor es la herramienta correcta.
Consulte PluginSource.h para las declaraciones normativas,
Schema/PhaseSchema.json para las tres fases de source y sus políticas, y
pluginsdk/examples/VirtualHeaderPlugin.c para un proveedor completo.