1 // Copyright (c) 2015-2016 The Khronos Group Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <cstdio>
16 #include <cstring>
17 #include <vector>
18
19 #include "source/spirv_target_env.h"
20 #include "spirv-tools/libspirv.h"
21 #include "tools/io.h"
22
print_usage(char * argv0)23 void print_usage(char* argv0) {
24 std::string target_env_list = spvTargetEnvList(19, 80);
25 printf(
26 R"(%s - Create a SPIR-V binary module from SPIR-V assembly text
27
28 Usage: %s [options] [<filename>]
29
30 The SPIR-V assembly text is read from <filename>. If no file is specified,
31 or if the filename is "-", then the assembly text is read from standard input.
32 The SPIR-V binary module is written to file "out.spv", unless the -o option
33 is used.
34
35 Options:
36
37 -h, --help Print this help.
38
39 -o <filename> Set the output filename. Use '-' to mean stdout.
40 --version Display assembler version information.
41 --preserve-numeric-ids
42 Numeric IDs in the binary will have the same values as in the
43 source. Non-numeric IDs are allocated by filling in the gaps,
44 starting with 1 and going up.
45 --target-env {%s}
46 Use specified environment.
47 )",
48 argv0, argv0, target_env_list.c_str());
49 }
50
51 static const auto kDefaultEnvironment = SPV_ENV_UNIVERSAL_1_5;
52
main(int argc,char ** argv)53 int main(int argc, char** argv) {
54 const char* inFile = nullptr;
55 const char* outFile = nullptr;
56 uint32_t options = 0;
57 spv_target_env target_env = kDefaultEnvironment;
58 for (int argi = 1; argi < argc; ++argi) {
59 if ('-' == argv[argi][0]) {
60 switch (argv[argi][1]) {
61 case 'h': {
62 print_usage(argv[0]);
63 return 0;
64 }
65 case 'o': {
66 if (!outFile && argi + 1 < argc) {
67 outFile = argv[++argi];
68 } else {
69 print_usage(argv[0]);
70 return 1;
71 }
72 } break;
73 case 0: {
74 // Setting a filename of "-" to indicate stdin.
75 if (!inFile) {
76 inFile = argv[argi];
77 } else {
78 fprintf(stderr, "error: More than one input file specified\n");
79 return 1;
80 }
81 } break;
82 case '-': {
83 // Long options
84 if (0 == strcmp(argv[argi], "--version")) {
85 printf("%s\n", spvSoftwareVersionDetailsString());
86 printf("Target: %s\n",
87 spvTargetEnvDescription(kDefaultEnvironment));
88 return 0;
89 } else if (0 == strcmp(argv[argi], "--help")) {
90 print_usage(argv[0]);
91 return 0;
92 } else if (0 == strcmp(argv[argi], "--preserve-numeric-ids")) {
93 options |= SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS;
94 } else if (0 == strcmp(argv[argi], "--target-env")) {
95 if (argi + 1 < argc) {
96 const auto env_str = argv[++argi];
97 if (!spvParseTargetEnv(env_str, &target_env)) {
98 fprintf(stderr, "error: Unrecognized target env: %s\n",
99 env_str);
100 return 1;
101 }
102 } else {
103 fprintf(stderr, "error: Missing argument to --target-env\n");
104 return 1;
105 }
106 } else {
107 fprintf(stderr, "error: Unrecognized option: %s\n\n", argv[argi]);
108 print_usage(argv[0]);
109 return 1;
110 }
111 } break;
112 default:
113 fprintf(stderr, "error: Unrecognized option: %s\n\n", argv[argi]);
114 print_usage(argv[0]);
115 return 1;
116 }
117 } else {
118 if (!inFile) {
119 inFile = argv[argi];
120 } else {
121 fprintf(stderr, "error: More than one input file specified\n");
122 return 1;
123 }
124 }
125 }
126
127 if (!outFile) {
128 outFile = "out.spv";
129 }
130
131 std::vector<char> contents;
132 if (!ReadFile<char>(inFile, "r", &contents)) return 1;
133
134 spv_binary binary;
135 spv_diagnostic diagnostic = nullptr;
136 spv_context context = spvContextCreate(target_env);
137 spv_result_t error = spvTextToBinaryWithOptions(
138 context, contents.data(), contents.size(), options, &binary, &diagnostic);
139 spvContextDestroy(context);
140 if (error) {
141 spvDiagnosticPrint(diagnostic);
142 spvDiagnosticDestroy(diagnostic);
143 return error;
144 }
145
146 if (!WriteFile<uint32_t>(outFile, "wb", binary->code, binary->wordCount)) {
147 spvBinaryDestroy(binary);
148 return 1;
149 }
150
151 spvBinaryDestroy(binary);
152
153 return 0;
154 }
155