vita-libs-gen.c (12919B)
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <sys/stat.h> 6 #include "vita-import.h" 7 8 #define KERNEL_LIBS_STUB "SceKernel" 9 10 typedef struct { 11 int num; 12 struct { 13 const char *name; 14 const char *postfix; 15 } names[1024]; 16 } libs_t; 17 18 void usage(); 19 int generate_assembly(vita_imports_t **imports, int imports_count); 20 int generate_makefile(vita_imports_t **imports, int imports_count); 21 int generate_cmake(vita_imports_t **imports, int imports_count); 22 23 int main(int argc, const char **argv) 24 { 25 int cmake = 0; 26 27 if (argc > 1 && strcmp(argv[1], "-c") == 0) { 28 cmake = 1; 29 argc--; 30 argv++; 31 } 32 33 if (argc < 3) { 34 usage(); 35 goto exit_failure; 36 } 37 38 int imports_count = argc - 2; 39 40 vita_imports_t **imports = malloc(sizeof(vita_imports_t*) * imports_count); 41 42 int i; 43 for (i = 0; i < imports_count; i++) 44 { 45 vita_imports_t *imp = vita_imports_load(argv[i + 1], 1); 46 47 if (imp == NULL) { 48 goto exit_failure; 49 } 50 51 imports[i] = imp; 52 } 53 54 #if defined(_WIN32) && !defined(__CYGWIN__) 55 mkdir(argv[argc - 1]); 56 #else 57 mkdir(argv[argc - 1], 0777); // create directory if it doesn't exist 58 #endif 59 60 if (chdir(argv[argc - 1])) { 61 perror(argv[argc - 1]); 62 goto exit_failure; 63 } 64 65 if (!generate_assembly(imports, imports_count)) { 66 fprintf(stderr, "Error generating the assembly file\n"); 67 goto exit_failure; 68 } 69 70 if (cmake) { 71 if (!generate_cmake(imports, imports_count)) { 72 fprintf(stderr, "Error generating the assembly makefile\n"); 73 goto exit_failure; 74 } 75 } else { 76 if (!generate_makefile(imports, imports_count)) { 77 fprintf(stderr, "Error generating the assembly makefile\n"); 78 goto exit_failure; 79 } 80 } 81 82 for (i = 0; i < imports_count; i++) 83 { 84 vita_imports_free(imports[i]); 85 } 86 87 free(imports); 88 89 return EXIT_SUCCESS; 90 exit_failure: 91 return EXIT_FAILURE; 92 } 93 94 95 int generate_assembly(vita_imports_t **imports, int imports_count) 96 { 97 char filename[128]; 98 FILE *fp; 99 int h, i, j, k; 100 101 for (h = 0; h < imports_count; h++) { 102 vita_imports_t *imp = imports[h]; 103 104 for (i = 0; i < imp->n_libs; i++) { 105 vita_imports_lib_t *library = imp->libs[i]; 106 for (j = 0; j < library->n_modules; j++) { 107 vita_imports_module_t *module = library->modules[j]; 108 109 for (k = 0; k < module->n_functions; k++) { 110 vita_imports_stub_t *function = module->functions[k]; 111 const char *fname = function->name; 112 char filename[4096]; 113 snprintf(filename, sizeof(filename), "%s_%s_%s%s.S", library->name, module->name, fname, imp->postfix); 114 if ((fp = fopen(filename, "w")) == NULL) 115 return 0; 116 fprintf(fp, ".arch armv7a\n\n"); 117 fprintf(fp, ".section .vitalink.fstubs.%s,\"ax\",%%progbits\n\n", module->name); 118 fprintf(fp, 119 "\t.align 4\n" 120 "\t.global %s\n" 121 "\t.type %s, %%function\n" 122 "%s:\n" 123 ".if GEN_WEAK_EXPORTS\n" 124 "\t.word 0x00000008\n" 125 ".else\n" 126 "\t.word 0x00000000\n" 127 ".endif //GEN_WEAK_EXPORTS\n" 128 "\t.word 0x%08X\n" 129 "\t.word 0x%08X\n" 130 "\t.align 4\n\n", 131 fname, fname, fname, 132 module->NID, 133 function->NID); 134 fclose(fp); 135 } 136 137 for (k = 0; k < module->n_variables; k++) { 138 vita_imports_stub_t *variable = module->variables[k]; 139 const char *vname = variable->name; 140 char filename[4096]; 141 snprintf(filename, sizeof(filename), "%s_%s_%s%s.S", library->name, module->name, vname, imp->postfix); 142 if ((fp = fopen(filename, "w")) == NULL) 143 return 0; 144 fprintf(fp, ".arch armv7a\n\n"); 145 fprintf(fp, ".section .vitalink.vstubs.%s,\"ax\",%%progbits\n\n",module->name); 146 fprintf(fp, 147 "\t.align 4\n" 148 "\t.global %s\n" 149 "\t.type %s, %%function\n" 150 "%s:\n" 151 ".if GEN_WEAK_EXPORTS\n" 152 "\t.word 0x00000008\n" 153 ".else\n" 154 "\t.word 0x00000000\n" 155 ".endif //GEN_WEAK_EXPORTS\n" 156 "\t.word 0x%08X\n" 157 "\t.word 0x%08X\n" 158 "\t.word 0\n" 159 "\t.word 0\n" 160 "\t.word 0\n" 161 "\t.word 0\n" 162 "\t.word 0\n" 163 "\t.align 4\n\n", 164 vname, vname, vname, 165 module->NID, 166 variable->NID); 167 fclose(fp); 168 } 169 } 170 } 171 } 172 173 return 1; 174 } 175 176 char *g_kernel_objs; 177 size_t g_special_size, g_special_written; 178 FILE *fp; 179 180 void write_symbol(const char *symbol, int is_kernel) 181 { 182 if (is_kernel) { 183 size_t len = strlen(symbol); 184 while (g_special_written + len >= g_special_size) { 185 g_special_size *= 2; 186 g_kernel_objs = realloc(g_kernel_objs, g_special_size); 187 } 188 strcat(g_kernel_objs, symbol); 189 g_special_written += len; 190 } 191 fprintf(fp, "%s", symbol); // write regardless if its kernel or not 192 } 193 194 void write_cmake_sources(FILE *fp, const char *modname, const char *postfix, vita_imports_module_t *library) 195 { 196 int k; 197 198 for (k = 0; k < library->n_functions; k++) { 199 vita_imports_stub_t *function = library->functions[k]; 200 fprintf(fp, "\t\"%s_%s_%s%s.S\"\n", modname, library->name, function->name, postfix); 201 } 202 for (k = 0; k < library->n_variables; k++) { 203 vita_imports_stub_t *variable = library->variables[k]; 204 fprintf(fp, "\t\"%s_%s_%s%s.S\"\n", modname, library->name, variable->name, postfix); 205 } 206 } 207 208 int generate_cmake_user(FILE *fp, const char *postfix, vita_imports_lib_t *module) 209 { 210 int i; 211 int found_libs = 0; 212 213 for (i = 0; i < module->n_modules; i++) 214 { 215 vita_imports_module_t *library = module->modules[i]; 216 217 // skip kernel 218 if (library->is_kernel) 219 continue; 220 221 if (!found_libs) 222 { 223 fprintf(fp, "set(%s%s_ASM\n", module->name, postfix); 224 found_libs = 1; 225 } 226 227 write_cmake_sources(fp, module->name, postfix, library); 228 } 229 230 if (found_libs) 231 { 232 fputs(")\n\n", fp); 233 } 234 235 return found_libs; 236 } 237 238 int generate_cmake_kernel(FILE *fp, const char *modname, const char *postfix, vita_imports_module_t *library) 239 { 240 if (!library->n_functions && !library->n_variables) 241 return 0; 242 243 fprintf(fp, "set(%s%s_ASM\n", library->name, postfix); 244 write_cmake_sources(fp, modname, postfix, library); 245 fputs(")\n\n", fp); 246 247 return 1; 248 } 249 250 int generate_cmake(vita_imports_t **imports, int imports_count) 251 { 252 int h, i, j, k; 253 int is_special; 254 255 // TODO: something dynamic 256 libs_t user_libs = {0}; 257 libs_t kernel_libs = {0}; 258 259 if ((fp = fopen("CMakeLists.txt", "w")) == NULL) { 260 return 0; 261 } 262 263 fputs( 264 "cmake_minimum_required(VERSION 2.8)\n\n" 265 "if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)\n" 266 "\tif(DEFINED ENV{VITASDK})\n" 267 "\t\tset(CMAKE_TOOLCHAIN_FILE \"$ENV{VITASDK}/share/vita.toolchain.cmake\" CACHE PATH \"toolchain file\")\n" 268 "\telse()\n" 269 "\t\tmessage(FATAL_ERROR \"Please define VITASDK to point to your SDK path!\")\n" 270 "\tendif()\n" 271 "endif()\n" 272 "project(vitalibs)\n" 273 "enable_language(ASM)\n\n", fp); 274 275 for (h = 0; h < imports_count; ++h) 276 { 277 vita_imports_t *imp = imports[h]; 278 279 for (i = 0; i < imp->n_libs; i++) 280 { 281 vita_imports_lib_t *module = imp->libs[i]; 282 283 // generate user libs first 284 if (generate_cmake_user(fp, imp->postfix, module)) 285 { 286 user_libs.names[user_libs.num].name = module->name; 287 user_libs.names[user_libs.num].postfix = imp->postfix; 288 user_libs.num++; 289 } 290 291 for (j = 0; j < imp->libs[i]->n_modules; j++) 292 { 293 vita_imports_module_t *library = imp->libs[i]->modules[j]; 294 295 if (!library->is_kernel) 296 continue; 297 298 if (generate_cmake_kernel(fp, module->name, imp->postfix, library)) 299 { 300 kernel_libs.names[kernel_libs.num].name = library->name; 301 kernel_libs.names[kernel_libs.num].postfix = imp->postfix; 302 kernel_libs.num++; 303 } 304 } 305 } 306 } 307 308 if (user_libs.num > 0) 309 { 310 fputs("set(USER_LIBRARIES\n", fp); 311 312 for (i = 0; i < user_libs.num; ++i) 313 { 314 fprintf(fp, "\t\"%s%s\"\n", user_libs.names[i].name, user_libs.names[i].postfix); 315 } 316 317 fputs(")\n\n", fp); 318 } 319 320 if (kernel_libs.num > 0) 321 { 322 fputs("set(KERNEL_LIBRARIES\n", fp); 323 324 for (i = 0; i < kernel_libs.num; ++i) 325 { 326 fprintf(fp, "\t\"%s%s\"\n", kernel_libs.names[i].name, kernel_libs.names[i].postfix); 327 } 328 329 fputs(")\n\n", fp); 330 } 331 332 if (user_libs.num > 0) 333 { 334 fputs( 335 "foreach(library ${USER_LIBRARIES})\n" 336 "\tadd_library(${library}_stub STATIC ${${library}_ASM})\n" 337 "\ttarget_compile_definitions(${library}_stub PRIVATE -DGEN_WEAK_EXPORTS=0)\n" 338 "\tadd_library(${library}_stub_weak STATIC ${${library}_ASM})\n" 339 "\ttarget_compile_definitions(${library}_stub_weak PRIVATE -DGEN_WEAK_EXPORTS=1)\n" 340 "endforeach(library)\n\n", fp); 341 } 342 343 if (kernel_libs.num > 0) 344 { 345 fputs( 346 "foreach(library ${KERNEL_LIBRARIES})\n" 347 "\tadd_library(${library}_stub STATIC ${${library}_ASM})\n" 348 "\ttarget_compile_definitions(${library}_stub PRIVATE -DGEN_WEAK_EXPORTS=0)\n" 349 "endforeach(library)\n\n", fp); 350 } 351 352 fclose(fp); 353 return 1; 354 } 355 356 int generate_makefile(vita_imports_t **imports, int imports_count) 357 { 358 int h, i, j, k; 359 int is_special; 360 361 if ((fp = fopen("Makefile", "w")) == NULL) { 362 return 0; 363 } 364 365 g_special_size = 1024; 366 g_special_written = 0; 367 g_kernel_objs = malloc(g_special_size); 368 g_kernel_objs[0] = '\0'; 369 370 fputs( 371 "ifdef VITASDK\n" 372 "PREFIX = $(VITASDK)/bin/\n" 373 "endif\n\n" 374 "ARCH ?= $(PREFIX)arm-vita-eabi\n" 375 "AS = $(ARCH)-as\n" 376 "AR = $(ARCH)-ar\n" 377 "RANLIB = $(ARCH)-ranlib\n\n" 378 "TARGETS =", fp); 379 380 for (h = 0; h < imports_count; h++) { 381 vita_imports_t *imp = imports[h]; 382 383 for (i = 0; i < imp->n_libs; i++) { 384 fprintf(fp, " lib%s%s_stub.a", imp->libs[i]->name, imp->postfix); 385 386 for (j = 0; j < imp->libs[i]->n_modules; j++) { 387 vita_imports_module_t *module = imp->libs[i]->modules[j]; 388 389 if (!module->is_kernel) 390 continue; 391 392 fprintf(fp, " lib%s%s_stub.a", module->name, imp->postfix); 393 } 394 } 395 } 396 397 fprintf(fp, "\nTARGETS_WEAK ="); 398 for (h = 0; h < imports_count; h++) { 399 vita_imports_t *imp = imports[h]; 400 401 for (i = 0; i < imp->n_libs; i++) { 402 fprintf(fp, " lib%s%s_stub_weak.a", imp->libs[i]->name, imp->postfix); 403 } 404 } 405 406 fprintf(fp, "\n\n"); 407 408 for (h = 0; h < imports_count; h++) { 409 vita_imports_t *imp = imports[h]; 410 411 for (i = 0; i < imp->n_libs; i++) { 412 vita_imports_lib_t *library = imp->libs[i]; 413 is_special = (strcmp(KERNEL_LIBS_STUB, library->name) == 0); 414 415 for (int weak = 0; weak < 2; weak++) { 416 if (!is_special) { 417 fprintf(fp, "%s%s =", library->name, weak ? "_weak_OBJS" : "_OBJS"); 418 } 419 420 for (j = 0; j < library->n_modules; j++) { 421 vita_imports_module_t *module = library->modules[j]; 422 423 if(module->is_kernel) 424 continue; 425 426 char buf[4096]; 427 for (k = 0; k < module->n_functions; k++) { 428 vita_imports_stub_t *function = module->functions[k]; 429 snprintf(buf, sizeof(buf), " %s_%s_%s%s.%s", library->name, module->name, function->name, imp->postfix, weak ? "wo" : "o"); 430 write_symbol(buf, is_special); 431 } 432 for (k = 0; k < module->n_variables; k++) { 433 vita_imports_stub_t *variable = module->variables[k]; 434 snprintf(buf, sizeof(buf), " %s_%s_%s%s.%s", library->name, module->name, variable->name, imp->postfix, weak ? "wo" : "o"); 435 write_symbol(buf, is_special); 436 } 437 } 438 439 if (!is_special) { 440 fprintf(fp, "\n"); 441 } 442 } 443 444 for (j = 0; j < library->n_modules; j++) { 445 vita_imports_module_t *module = library->modules[j]; 446 447 if (!module->is_kernel) 448 continue; 449 450 char buf[4096]; 451 452 fprintf(fp, "%s_OBJS =", module->name); 453 454 for (k = 0; k < module->n_functions; k++) { 455 vita_imports_stub_t *function = module->functions[k]; 456 snprintf(buf, sizeof(buf), " %s_%s_%s%s.o", library->name, module->name, function->name, imp->postfix); 457 write_symbol(buf, 1); 458 } 459 460 for (k = 0; k < module->n_variables; k++) { 461 vita_imports_stub_t *variable = module->variables[k]; 462 snprintf(buf, sizeof(buf), " %s_%s_%s%s.o", library->name, module->name, variable->name, imp->postfix); 463 write_symbol(buf, 1); 464 } 465 466 fprintf(fp, "\n"); 467 } 468 } 469 } 470 471 // write kernel lib stub 472 fprintf(fp, "%s_OBJS =%s\n", KERNEL_LIBS_STUB, g_kernel_objs); 473 474 fputs( 475 "ALL_OBJS=\n\n" 476 "all: $(TARGETS) $(TARGETS_WEAK)\n\n" 477 "define LIBRARY_template\n" 478 " $(1): $$($(1:lib%_stub.a=%)_OBJS)\n" 479 " ALL_OBJS += $$($(1:lib%_stub.a=%)_OBJS)\n" 480 "endef\n" 481 "define LIBRARY_WEAK_template\n" 482 " $(1): $$($(1:lib%_stub_weak.a=%)_weak_OBJS)\n" 483 " ALL_OBJS += $$($(1:lib%_stub_weak.a=%)_weak_OBJS)\n" 484 "endef\n\n" 485 "$(foreach library,$(TARGETS),$(eval $(call LIBRARY_template,$(library))))\n" 486 "$(foreach library,$(TARGETS_WEAK),$(eval $(call LIBRARY_WEAK_template,$(library))))\n\n" 487 "install: $(TARGETS) $(TARGETS_WEAK)\n" 488 "\tcp $(TARGETS) $(VITASDK)/arm-vita-eabi/lib\n" 489 "\tcp $(TARGETS_WEAK) $(VITASDK)/arm-vita-eabi/lib\n\n" 490 "clean:\n" 491 "\trm -f $(TARGETS) $(TARGETS_WEAK) $(ALL_OBJS)\n\n" 492 "$(TARGETS) $(TARGETS_WEAK):\n" 493 "\t$(AR) cru $@ $?\n" 494 "\t$(RANLIB) $@\n\n" 495 "%.o: %.S\n" 496 "\t$(AS) --defsym GEN_WEAK_EXPORTS=0 $< -o $@\n\n" 497 "%.wo: %.S\n" 498 "\t$(AS) --defsym GEN_WEAK_EXPORTS=1 $< -o $@\n" 499 , fp); 500 501 fclose(fp); 502 free(g_kernel_objs); 503 504 return 1; 505 } 506 507 void usage() 508 { 509 fprintf(stderr, 510 "vita-libs-gen by xerpi\n" 511 "usage: vita-libs-gen [-c] nids.yml [extra.yml ...] output-dir\n" 512 "\t-c: Generate CMakeLists.txt instead of a Makefile\n" 513 ); 514 }