Generate the main C function.

This function:

  • allocate the Sys object if it exists
  • call init if is exists
  • call main if it exists

Property definitions

nitc $ AbstractCompiler :: compile_main_function
	# Generate the main C function.
	#
	# This function:
	#
	# * allocate the Sys object if it exists
	# * call init if is exists
	# * call main if it exists
	fun compile_main_function
	do
		var v = self.new_visitor
		v.add_decl("#include <signal.h>")
		var platform = target_platform

		var no_main = platform.no_main or modelbuilder.toolcontext.opt_no_main.value

		if platform.supports_libunwind then
			v.add_decl("#ifndef NO_STACKTRACE")
			v.add_decl("#define UNW_LOCAL_ONLY")
			v.add_decl("#include <libunwind.h>")
			v.add_decl("#include \"c_functions_hash.h\"")
			v.add_decl("#endif")
		end
		v.add_decl("int glob_argc;")
		v.add_decl("char **glob_argv;")
		v.add_decl("val *glob_sys;")

		# Store catch stack in thread local storage
		v.add_decl """
#if defined(TARGET_OS_IPHONE)
	// Use pthread_key_create and others for iOS
	#include <pthread.h>

	static pthread_key_t catch_stack_key;
	static pthread_once_t catch_stack_key_created = PTHREAD_ONCE_INIT;

	static void create_catch_stack()
	{
		pthread_key_create(&catch_stack_key, NULL);
	}

	struct catch_stack_t *getCatchStack()
	{
		pthread_once(&catch_stack_key_created, &create_catch_stack);
		struct catch_stack_t *data = pthread_getspecific(catch_stack_key);
		if (data == NULL) {
			data = malloc(sizeof(struct catch_stack_t));
			data->cursor = -1;
			data->currentSize = 0;
			data->envs = NULL;
			pthread_setspecific(catch_stack_key, data);
		}
		return data;
	}
#else
	// Use __thread when available
	__thread struct catch_stack_t catchStack = {-1, 0, NULL};

	struct catch_stack_t *getCatchStack()
	{
		return &catchStack;
	}
#endif
"""

		if self.modelbuilder.toolcontext.opt_typing_test_metrics.value then
			for tag in count_type_test_tags do
				v.add_decl("long count_type_test_resolved_{tag};")
				v.add_decl("long count_type_test_unresolved_{tag};")
				v.add_decl("long count_type_test_skipped_{tag};")
				v.compiler.header.add_decl("extern long count_type_test_resolved_{tag};")
				v.compiler.header.add_decl("extern long count_type_test_unresolved_{tag};")
				v.compiler.header.add_decl("extern long count_type_test_skipped_{tag};")
			end
		end

		if self.modelbuilder.toolcontext.opt_invocation_metrics.value then
			v.add_decl("long count_invoke_by_tables;")
			v.add_decl("long count_invoke_by_direct;")
			v.add_decl("long count_invoke_by_inline;")
			v.compiler.header.add_decl("extern long count_invoke_by_tables;")
			v.compiler.header.add_decl("extern long count_invoke_by_direct;")
			v.compiler.header.add_decl("extern long count_invoke_by_inline;")
		end

		if self.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
			v.add_decl("long count_attr_reads = 0;")
			v.add_decl("long count_isset_checks = 0;")
			v.compiler.header.add_decl("extern long count_attr_reads;")
			v.compiler.header.add_decl("extern long count_isset_checks;")
		end

		v.add_decl("static void show_backtrace(void) \{")
		if platform.supports_libunwind then
			v.add_decl("#ifndef NO_STACKTRACE")
			v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
			v.add_decl("unw_cursor_t cursor;")
			v.add_decl("if(opt==NULL)\{")
			v.add_decl("unw_context_t uc;")
			v.add_decl("unw_word_t ip;")
			v.add_decl("char* procname = malloc(sizeof(char) * 100);")
			v.add_decl("unw_getcontext(&uc);")
			v.add_decl("unw_init_local(&cursor, &uc);")
			v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
			v.add_decl("PRINT_ERROR(\"--   Stack Trace   ------------------------------\\n\");")
			v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
			v.add_decl("while (unw_step(&cursor) > 0) \{")
			v.add_decl("	unw_get_proc_name(&cursor, procname, 100, &ip);")
			v.add_decl("	const char* recv = get_nit_name(procname, strlen(procname));")
			v.add_decl("	if (recv != NULL)\{")
			v.add_decl("		PRINT_ERROR(\"` %s\\n\", recv);")
			v.add_decl("	\}else\{")
			v.add_decl("		PRINT_ERROR(\"` %s\\n\", procname);")
			v.add_decl("	\}")
			v.add_decl("\}")
			v.add_decl("PRINT_ERROR(\"-------------------------------------------------\\n\");")
			v.add_decl("free(procname);")
			v.add_decl("\}")
			v.add_decl("#endif /* NO_STACKTRACE */")
		end
		v.add_decl("\}")

		v.add_decl("void sig_handler(int signo)\{")
		v.add_decl "#ifdef _WIN32"
		v.add_decl "PRINT_ERROR(\"Caught signal : %s\\n\", signo);"
		v.add_decl "#else"
		v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));")
		v.add_decl "#endif"
		v.add_decl("show_backtrace();")
		# rethrows
		v.add_decl("signal(signo, SIG_DFL);")
		v.add_decl "#ifndef _WIN32"
		v.add_decl("kill(getpid(), signo);")
		v.add_decl "#endif"
		v.add_decl("\}")

		v.add_decl("void fatal_exit(int status) \{")
		v.add_decl("show_backtrace();")
		v.add_decl("exit(status);")
		v.add_decl("\}")

		compile_before_main(v)

		if no_main then
			v.add_decl("int nit_main(int argc, char** argv) \{")
		else
			v.add_decl("int main(int argc, char** argv) \{")
		end

		compile_begin_main(v)

		v.add "#if !defined(__ANDROID__) && !defined(TARGET_OS_IPHONE)"
		v.add("signal(SIGABRT, sig_handler);")
		v.add("signal(SIGFPE, sig_handler);")
		v.add("signal(SIGILL, sig_handler);")
		v.add("signal(SIGINT, sig_handler);")
		v.add("signal(SIGTERM, sig_handler);")
		v.add("signal(SIGSEGV, sig_handler);")
		v.add "#endif"
		v.add "#ifndef _WIN32"
		v.add("signal(SIGPIPE, SIG_IGN);")
		v.add "#endif"

		v.add("glob_argc = argc; glob_argv = argv;")
		v.add("initialize_gc_option();")

		v.add "initialize_nitni_global_refs();"

		var main_type = mainmodule.sys_type
		if main_type != null then
			var mainmodule = v.compiler.mainmodule
			var glob_sys = v.init_instance(main_type)
			v.add("glob_sys = {glob_sys};")
			var main_init = mainmodule.try_get_primitive_method("init", main_type.mclass)
			if main_init != null then
				v.send(main_init, [glob_sys])
			end
			var main_method = mainmodule.try_get_primitive_method("run", main_type.mclass) or else
				mainmodule.try_get_primitive_method("main", main_type.mclass)
			if main_method != null then
				v.send(main_method, [glob_sys])
			end
		end

		if self.modelbuilder.toolcontext.opt_typing_test_metrics.value then
			v.add_decl("long count_type_test_resolved_total = 0;")
			v.add_decl("long count_type_test_unresolved_total = 0;")
			v.add_decl("long count_type_test_skipped_total = 0;")
			v.add_decl("long count_type_test_total_total = 0;")
			for tag in count_type_test_tags do
				v.add_decl("long count_type_test_total_{tag};")
				v.add("count_type_test_total_{tag} = count_type_test_resolved_{tag} + count_type_test_unresolved_{tag} + count_type_test_skipped_{tag};")
				v.add("count_type_test_resolved_total += count_type_test_resolved_{tag};")
				v.add("count_type_test_unresolved_total += count_type_test_unresolved_{tag};")
				v.add("count_type_test_skipped_total += count_type_test_skipped_{tag};")
				v.add("count_type_test_total_total += count_type_test_total_{tag};")
			end
			v.add("printf(\"# dynamic count_type_test: total %l\\n\");")
			v.add("printf(\"\\tresolved\\tunresolved\\tskipped\\ttotal\\n\");")
			var tags = count_type_test_tags.to_a
			tags.add("total")
			for tag in tags do
				v.add("printf(\"{tag}\");")
				v.add("printf(\"\\t%ld (%.2f%%)\", count_type_test_resolved_{tag}, 100.0*count_type_test_resolved_{tag}/count_type_test_total_total);")
				v.add("printf(\"\\t%ld (%.2f%%)\", count_type_test_unresolved_{tag}, 100.0*count_type_test_unresolved_{tag}/count_type_test_total_total);")
				v.add("printf(\"\\t%ld (%.2f%%)\", count_type_test_skipped_{tag}, 100.0*count_type_test_skipped_{tag}/count_type_test_total_total);")
				v.add("printf(\"\\t%ld (%.2f%%)\\n\", count_type_test_total_{tag}, 100.0*count_type_test_total_{tag}/count_type_test_total_total);")
			end
		end

		if self.modelbuilder.toolcontext.opt_invocation_metrics.value then
			v.add_decl("long count_invoke_total;")
			v.add("count_invoke_total = count_invoke_by_tables + count_invoke_by_direct + count_invoke_by_inline;")
			v.add("printf(\"# dynamic count_invocation: total %ld\\n\", count_invoke_total);")
			v.add("printf(\"by table: %ld (%.2f%%)\\n\", count_invoke_by_tables, 100.0*count_invoke_by_tables/count_invoke_total);")
			v.add("printf(\"direct:   %ld (%.2f%%)\\n\", count_invoke_by_direct, 100.0*count_invoke_by_direct/count_invoke_total);")
			v.add("printf(\"inlined:  %ld (%.2f%%)\\n\", count_invoke_by_inline, 100.0*count_invoke_by_inline/count_invoke_total);")
		end

		if self.modelbuilder.toolcontext.opt_isset_checks_metrics.value then
			v.add("printf(\"# dynamic attribute reads: %ld\\n\", count_attr_reads);")
			v.add("printf(\"# dynamic isset checks: %ld\\n\", count_isset_checks);")
		end

		v.add("return 0;")
		v.add("\}")

		for m in mainmodule.in_importation.greaters do
			var f = "FILE_"+m.c_name
			v.add "const char {f}[] = \"{m.location.file.filename.escape_to_c}\";"
			provide_declaration(f, "extern const char {f}[];")
		end
	end
src/compiler/abstract_compiler.nit:891,2--1122,4