Linker usability improvements (#4084)

* tools/linker: Error out on unrecognized options

Fixes #4083.

* tools/linker: Use early returns when parsing options

This was already the case for some linker options, and other tools were
doing so for all of their options.

* tools/linker: Rework the usage output

* The new formatting for long options taking a value makes it explicit
  that there is no equal sign between the option name and the value.
* The options are sorted by lexicographical order.
* Change the option formatting from 90 columns to 80, to match the other
  tools.

* tools/linker: Change the default environment to spv1.5

* tools/linker: Change the default output to spv.out

Instead of writing to the standard output when the "-o" option is not
specified, the resulting linked SPIR-V binary will be written to
"spv.out".
One can still have the output sent to the standard output by specifying
"-o -".

* tools/linker: Update the reported target for --version

Running `spirv-link --version` will now report the currently selected
environment.

* tools/linker: Sort header includes

* linker: Improve module-related error messages

* Use 1-based indexing of modules;
* Say which module could not be built;
* Use the correct total number of input modules in the error message
  when one fails to build.
This commit is contained in:
Pierre Moreau 2021-01-13 15:05:40 +01:00 committed by GitHub
parent 7bbe1a3164
commit b1507d0d2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 57 additions and 47 deletions

View File

@ -676,14 +676,15 @@ spv_result_t Link(const Context& context, const uint32_t* const* binaries,
if (schema != 0u) {
position.index = 4u;
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
<< "Schema is non-zero for module " << i << ".";
<< "Schema is non-zero for module " << i + 1 << ".";
}
std::unique_ptr<IRContext> ir_context = BuildModule(
c_context->target_env, consumer, binaries[i], binary_sizes[i]);
if (ir_context == nullptr)
return DiagnosticStream(position, consumer, "", SPV_ERROR_INVALID_BINARY)
<< "Failed to build a module out of " << ir_contexts.size() << ".";
<< "Failed to build module " << i + 1 << " out of " << num_binaries
<< ".";
modules.push_back(ir_context->module());
ir_contexts.push_back(std::move(ir_context));
}

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "spirv-tools/linker.hpp"
#include <cstring>
#include <iostream>
#include <vector>
@ -19,42 +21,56 @@
#include "source/spirv_target_env.h"
#include "source/table.h"
#include "spirv-tools/libspirv.hpp"
#include "spirv-tools/linker.hpp"
#include "tools/io.h"
void print_usage(char* argv0) {
std::string target_env_list = spvTargetEnvList(27, 95);
namespace {
const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
void print_usage(const char* program) {
std::string target_env_list = spvTargetEnvList(16, 80);
// NOTE: Please maintain flags in lexicographical order.
printf(
R"(%s - Link SPIR-V binary files together.
USAGE: %s [options] <filename> [<filename> ...]
USAGE: %s [options] [-o <output>] <input>...
The SPIR-V binaries are read from the different <filename>.
The SPIR-V binaries are read from the different <input>(s).
The SPIR-V resulting linked binary module is written to the file "out.spv"
unless the -o option is used; if <output> is "-", it is written to the standard
output.
NOTE: The linker is a work in progress.
Options:
-h, --help Print this help.
-o Name of the resulting linked SPIR-V binary.
--create-library Link the binaries into a library, keeping all exported symbols.
--allow-partial-linkage Allow partial linkage by accepting imported symbols to be unresolved.
--verify-ids Verify that IDs in the resulting modules are truly unique.
--version Display linker version information
--target-env {%s}
Use validation rules from the specified environment.
Options (in lexicographical order):
--allow-partial-linkage
Allow partial linkage by accepting imported symbols to be
unresolved.
--create-library
Link the binaries into a library, keeping all exported symbols.
-h, --help
Print this help.
--target-env <env>
Set the target environment. Without this flag the target
environment defaults to spv1.5. <env> must be one of
{%s}
--verify-ids
Verify that IDs in the resulting modules are truly unique.
--version
Display linker version information
)",
argv0, argv0, target_env_list.c_str());
program, program, target_env_list.c_str());
}
} // namespace
int main(int argc, char** argv) {
std::vector<const char*> inFiles;
const char* outFile = nullptr;
spv_target_env target_env = SPV_ENV_UNIVERSAL_1_0;
spv_target_env target_env = kDefaultEnvironment;
spvtools::LinkerOptions options;
bool continue_processing = true;
int return_code = 0;
for (int argi = 1; continue_processing && argi < argc; ++argi) {
for (int argi = 1; argi < argc; ++argi) {
const char* cur_arg = argv[argi];
if ('-' == cur_arg[0]) {
if (0 == strcmp(cur_arg, "-o")) {
@ -63,55 +79,48 @@ int main(int argc, char** argv) {
outFile = argv[++argi];
} else {
fprintf(stderr, "error: More than one output file specified\n");
continue_processing = false;
return_code = 1;
return 1;
}
} else {
fprintf(stderr, "error: Missing argument to %s\n", cur_arg);
continue_processing = false;
return_code = 1;
return 1;
}
} else if (0 == strcmp(cur_arg, "--create-library")) {
options.SetCreateLibrary(true);
} else if (0 == strcmp(cur_arg, "--verify-ids")) {
options.SetVerifyIds(true);
} else if (0 == strcmp(cur_arg, "--allow-partial-linkage")) {
options.SetAllowPartialLinkage(true);
} else if (0 == strcmp(cur_arg, "--version")) {
printf("%s\n", spvSoftwareVersionDetailsString());
// TODO(dneto): Add OpenCL 2.2 at least.
printf("Targets:\n %s\n %s\n %s\n",
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_1),
spvTargetEnvDescription(SPV_ENV_VULKAN_1_0),
spvTargetEnvDescription(SPV_ENV_UNIVERSAL_1_2));
continue_processing = false;
return_code = 0;
} else if (0 == strcmp(cur_arg, "--create-library")) {
options.SetCreateLibrary(true);
} else if (0 == strcmp(cur_arg, "--help") || 0 == strcmp(cur_arg, "-h")) {
print_usage(argv[0]);
continue_processing = false;
return_code = 0;
return 0;
} else if (0 == strcmp(cur_arg, "--target-env")) {
if (argi + 1 < argc) {
const auto env_str = argv[++argi];
if (!spvParseTargetEnv(env_str, &target_env)) {
fprintf(stderr, "error: Unrecognized target env: %s\n", env_str);
continue_processing = false;
return_code = 1;
return 1;
}
} else {
fprintf(stderr, "error: Missing argument to --target-env\n");
continue_processing = false;
return_code = 1;
return 1;
}
} else if (0 == strcmp(cur_arg, "--verify-ids")) {
options.SetVerifyIds(true);
} else if (0 == strcmp(cur_arg, "--version")) {
printf("%s\n", spvSoftwareVersionDetailsString());
printf("Target: %s\n", spvTargetEnvDescription(target_env));
return 0;
} else {
fprintf(stderr, "error: Unrecognized option: %s\n\n", argv[argi]);
print_usage(argv[0]);
return 1;
}
} else {
inFiles.push_back(cur_arg);
}
}
// Exit if command line parsing was not successful.
if (!continue_processing) {
return return_code;
if (!outFile) {
outFile = "out.spv";
}
if (inFiles.empty()) {