vita-toolchain

git clone https://git.neptards.moe/neptards/vita-toolchain.git
Log | Files | Refs | README | LICENSE

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 }