cpp.c (7292B)
1 #include <kit/compile.h> 2 #include <kit/core.h> 3 #include <kit/preprocess.h> 4 #include <stdint.h> 5 6 #include "cflags.h" 7 #include "driver.h" 8 9 /* `kit cpp` — standalone C preprocessor. Reads one C source (path or 10 * `-` for stdin), writes the preprocessed token stream to `-o PATH` or 11 * stdout. Feature-equivalent to `kit cc -E` but without cc's source- 12 * classification / link-input scaffolding. 13 * 14 * Flag surface is the cflags subset shared with cc + as: 15 * -I DIR, -IDIR user include path 16 * -isystem DIR system include path 17 * -D NAME[=BODY] define 18 * -U NAME undefine 19 * -o PATH output (default: stdout) 20 * -target TRIPLE cross-target (default: host) 21 * - stdin source 22 * 23 * The classical cpp-only flags (-P, -dM, -C, -CC) are not yet supported 24 * by kit's preprocessor — they would land equally in `kit cc -E`. */ 25 26 #define CPP_TOOL "cpp" 27 28 typedef struct CppOptions { 29 const char* output_path; 30 const char* source_path; /* NULL when stdin source */ 31 int from_stdin; 32 KitTargetSpec target; 33 } CppOptions; 34 35 void driver_help_cpp(void) { 36 driver_printf( 37 "%.*s", 38 KIT_SLICE_ARG(KIT_SLICE_LIT( 39 "kit cpp — standalone C preprocessor\n" 40 "\n" 41 "USAGE\n" 42 " kit cpp [options] INPUT.c\n" 43 " kit cpp [options] - (read from stdin)\n" 44 "\n" 45 "DESCRIPTION\n" 46 " Runs the C preprocessor on a single input and writes the " 47 "resulting\n" 48 " token stream to -o (or stdout when -o is absent). Functionally\n" 49 " equivalent to `kit cc -E` but without cc's link/source-input\n" 50 " classification.\n" 51 "\n" 52 "OPTIONS\n" 53 " -o PATH Output path (default: stdout)\n" 54 " -I DIR, -IDIR Add a user include directory\n" 55 " -isystem DIR Add a system include directory\n" 56 " -D NAME[=BODY] Define a preprocessor macro\n" 57 " -U NAME Undefine a preprocessor macro\n" 58 " -target TRIPLE Cross-target. See `kit cc --help` for the\n" 59 " accepted arches/OSes. Default: host.\n" 60 " -h, --help Show this help and exit\n" 61 "\n" 62 "EXIT CODES\n" 63 " 0 success 1 preprocess / I/O error 2 " 64 "bad " 65 "usage\n"))); 66 } 67 68 static void cpp_usage(void) { 69 driver_errf(CPP_TOOL, "%.*s", 70 KIT_SLICE_ARG(KIT_SLICE_LIT( 71 "usage: kit cpp [options] INPUT.c\n" 72 " kit cpp --help for full option reference"))); 73 } 74 75 static int cpp_parse(int argc, char** argv, CppOptions* o, DriverEnv* env, 76 DriverCflags* cf, DriverTargetFeatures* tf) { 77 int i; 78 79 o->target = driver_host_target(); 80 81 for (i = 1; i < argc; ++i) { 82 const char* a = argv[i]; 83 int r; 84 85 r = driver_cflags_try_consume(cf, env, CPP_TOOL, argc, argv, &i); 86 if (r < 0) return 1; 87 if (r > 0) continue; 88 89 if (driver_streq(a, "-o")) { 90 if (++i >= argc) { 91 driver_errf(CPP_TOOL, "-o requires an argument"); 92 return 1; 93 } 94 o->output_path = argv[i]; 95 continue; 96 } 97 98 if (driver_streq(a, "-target")) { 99 if (++i >= argc) { 100 driver_errf(CPP_TOOL, "-target requires an argument"); 101 return 1; 102 } 103 if (driver_target_from_triple(argv[i], &o->target) != 0) { 104 driver_errf(CPP_TOOL, "unrecognized target: %.*s", 105 KIT_SLICE_ARG(kit_slice_cstr(argv[i]))); 106 return 1; 107 } 108 continue; 109 } 110 111 { 112 int tr = 113 driver_target_features_try_consume(tf, env, CPP_TOOL, argc, argv, &i); 114 if (tr < 0) return 1; 115 if (tr > 0) continue; 116 } 117 118 if (driver_streq(a, "-")) { 119 if (o->source_path || o->from_stdin) { 120 driver_errf(CPP_TOOL, "multiple inputs not supported"); 121 return 1; 122 } 123 o->from_stdin = 1; 124 continue; 125 } 126 127 if (a[0] == '-' && a[1] != '\0') { 128 driver_errf(CPP_TOOL, "unknown flag: %.*s", 129 KIT_SLICE_ARG(kit_slice_cstr(a))); 130 return 1; 131 } 132 133 if (o->source_path || o->from_stdin) { 134 driver_errf(CPP_TOOL, "multiple inputs not supported"); 135 return 1; 136 } 137 o->source_path = a; 138 } 139 140 if (!o->source_path && !o->from_stdin) { 141 driver_errf(CPP_TOOL, "no input file"); 142 cpp_usage(); 143 return 1; 144 } 145 return 0; 146 } 147 148 int driver_cpp(int argc, char** argv) { 149 DriverEnv env; 150 CppOptions o = {0}; 151 DriverCflags cf = {0}; 152 DriverTargetFeatures tf = {0}; 153 KitContext ctx; 154 KitPreprocessOptions pp; 155 KitTarget* target = NULL; 156 KitCompiler* compiler = NULL; 157 KitWriter* writer = NULL; 158 KitFileData src = {0}; 159 KitSlice input; 160 KitSlice input_name = KIT_SLICE_NULL; 161 uint8_t* stdin_buf = NULL; 162 size_t stdin_size = 0; 163 int rc = 1; 164 int loaded = 0; 165 166 if (argc < 2 || driver_argv_wants_help(argc, argv, 1)) { 167 driver_help_cpp(); 168 return 0; 169 } 170 171 driver_env_init(&env); 172 173 if (driver_cflags_init(&cf, &env, argc) != 0 || 174 driver_target_features_init(&tf, &env, argc) != 0) { 175 driver_errf(CPP_TOOL, "out of memory"); 176 driver_target_features_fini(&tf, &env); 177 driver_cflags_fini(&cf, &env); 178 driver_env_fini(&env); 179 return 2; 180 } 181 182 if (cpp_parse(argc, argv, &o, &env, &cf, &tf) != 0) { 183 driver_target_features_fini(&tf, &env); 184 driver_cflags_fini(&cf, &env); 185 driver_env_fini(&env); 186 return 2; 187 } 188 driver_cflags_fill_pp(&cf, &pp); 189 190 ctx = driver_env_to_context(&env); 191 192 if (o.from_stdin) { 193 if (!driver_read_stdin(&env, &stdin_buf, &stdin_size)) { 194 driver_errf(CPP_TOOL, "failed to read stdin"); 195 goto out; 196 } 197 input_name = KIT_SLICE_LIT("<stdin>"); 198 input.data = stdin_buf; 199 input.len = stdin_size; 200 } else { 201 if (ctx.file_io->read_all(ctx.file_io->user, o.source_path, &src) != 202 KIT_OK) { 203 driver_errf(CPP_TOOL, "failed to read: %.*s", 204 KIT_SLICE_ARG(kit_slice_cstr(o.source_path))); 205 goto out; 206 } 207 loaded = 1; 208 input_name = kit_slice_cstr(o.source_path); 209 input.data = src.data; 210 input.len = src.size; 211 } 212 213 if (o.output_path) { 214 if (ctx.file_io->open_writer(ctx.file_io->user, o.output_path, &writer) != 215 KIT_OK) { 216 driver_errf(CPP_TOOL, "failed to open output: %.*s", 217 KIT_SLICE_ARG(kit_slice_cstr(o.output_path))); 218 goto out; 219 } 220 } else { 221 writer = driver_stdout_writer(&env); 222 if (!writer) { 223 driver_errf(CPP_TOOL, "out of memory"); 224 goto out; 225 } 226 } 227 228 if (driver_target_new(&ctx, o.target, &tf, CPP_TOOL, &target) != KIT_OK || 229 driver_compiler_new(target, &ctx, &compiler) != KIT_OK) { 230 driver_errf(CPP_TOOL, "failed to initialize compiler"); 231 goto out; 232 } 233 234 rc = kit_cpp_preprocess(compiler, &pp, input_name, &input, writer) == KIT_OK 235 ? 0 236 : 1; 237 238 out: 239 if (compiler) driver_compiler_free(compiler); 240 kit_target_free(target); 241 if (writer) kit_writer_close(writer); 242 if (loaded) ctx.file_io->release(ctx.file_io->user, &src); 243 if (stdin_buf) driver_free(&env, stdin_buf, stdin_size); 244 driver_target_features_fini(&tf, &env); 245 driver_cflags_fini(&cf, &env); 246 driver_env_fini(&env); 247 return rc; 248 }