#define CHAZ_USE_SHORT_NAMES
#include <string.h>
#include <stdlib.h>
#include "Charmonizer/Core/Util.h"
#include "Charmonizer/Core/Compiler.h"
#include "Charmonizer/Core/CompilerSpec.h"
#include "Charmonizer/Core/OperSys.h"
extern chaz_bool_t chaz_ModHand_charm_run_available;
static void
destroy(Compiler *self);
static chaz_bool_t
compile_exe(Compiler *self, const char *source_path, const char *exe_path,
const char *code, size_t code_len);
static chaz_bool_t
compile_obj(Compiler *self, const char *source_path, const char *obj_path,
const char *code, size_t code_len);
static void
add_inc_dir(Compiler *self, const char *dir);
static void
test_compile(Compiler *self);
chaz_Compiler*
chaz_CC_new(OperSys *oper_sys, const char *cc_command, const char *cc_flags)
{
CompilerSpec *compiler_spec = CCSpec_find_spec();
Compiler *self = (Compiler*)malloc(sizeof(Compiler));
if (verbosity)
printf("Creating compiler object...\n");
/* assign */
self->os = oper_sys;
self->cc_command = strdup(cc_command);
self->cc_flags = strdup(cc_flags);
/* init */
self->buf = NULL;
self->buf_len = 0;
self->compile_exe = compile_exe;
self->compile_obj = compile_obj;
self->add_inc_dir = add_inc_dir;
self->destroy = destroy;
self->inc_dirs = (char**)calloc(sizeof(char*), 1);
/* set compiler-specific vars */
self->include_flag = strdup(compiler_spec->include_flag);
self->object_flag = strdup(compiler_spec->object_flag);
self->exe_flag = strdup(compiler_spec->exe_flag);
/* add the current directory as an include dir */
self->add_inc_dir(self, ".");
/* if we can't compile anything, game over */
test_compile(self);
return self;
}
static void
destroy(Compiler *self)
{
char **inc_dirs;
for (inc_dirs = self->inc_dirs; *inc_dirs != NULL; inc_dirs++) {
free(*inc_dirs);
}
free(self->inc_dirs);
free(self->buf);
free(self->cc_command);
free(self->cc_flags);
free(self->include_flag);
free(self->object_flag);
free(self->exe_flag);
free(self);
}
static chaz_bool_t
compile_exe(Compiler *self, const char *source_path, const char *exe_path,
const char *code, size_t code_len)
{
chaz_bool_t successful;
OperSys *os = self->os;
char *exe_full_filepath = NULL;
char **inc_dirs;
/* tack the exe_ext onto the path */
join_strings(&exe_full_filepath, 0, exe_path, os->exe_ext, NULL);
/* write the source file */
write_file(source_path, code, code_len);
/* prepare the compiler command */
if (verbosity < 2 && chaz_ModHand_charm_run_available) {
self->buf_len = join_strings(&(self->buf), self->buf_len,
os->local_command_start, "_charm_run ", self->cc_command, " ",
source_path, " ", self->exe_flag, exe_full_filepath, " ", NULL);
}
else {
self->buf_len = join_strings(&(self->buf), self->buf_len,
self->cc_command, " ", source_path, " ", self->exe_flag,
exe_full_filepath, " ", NULL);
}
for (inc_dirs = self->inc_dirs; *inc_dirs != NULL; inc_dirs++) {
self->buf_len = append_strings(&(self->buf), self->buf_len,
self->include_flag, *inc_dirs, " ", NULL);
}
self->buf_len = append_strings(&(self->buf), self->buf_len,
self->cc_flags, " ", NULL);
/* execute the compiler command and detect success/failure */
system(self->buf);
successful = can_open_file(exe_full_filepath);
free(exe_full_filepath);
return successful;
}
static chaz_bool_t
compile_obj(Compiler *self, const char *source_path, const char *obj_path,
const char *code, size_t code_len)
{
chaz_bool_t successful;
OperSys *os = self->os;
char *obj_full_filepath = NULL;
/* tack the obj_ext onto the path */
join_strings(&obj_full_filepath, 0, obj_path, os->obj_ext, NULL);
/* write the source file */
write_file(source_path, code, code_len);
/* compile the source */
if (verbosity < 2 && chaz_ModHand_charm_run_available) {
join_strings(&(self->buf), self->buf_len,
os->local_command_start, "_charm_run ", self->cc_command, " ",
source_path, " ", self->object_flag, obj_full_filepath, " ",
self->include_flag, ". ", self->cc_flags, NULL);
}
else {
join_strings(&(self->buf), self->buf_len,
self->cc_command, " ", source_path, " ", self->object_flag,
obj_full_filepath, " ", self->include_flag, ". ", self->cc_flags,
NULL);
}
system(self->buf);
/* see if compilation was successful */
successful = can_open_file(obj_full_filepath);
free(obj_full_filepath);
return successful;
}
static void
test_compile(Compiler *self)
{
char *code = "int main() { return 0; }\n";
chaz_bool_t success;
if (verbosity)
printf("Trying to compile a small test file...\n");
/* attempt compilation */
success = self->compile_exe(self, "_charm_try.c",
"_charm_try", code, strlen(code));
if (!success)
die("Failed to compile a small test file");
/* clean up */
remove("_charm_try.c");
self->os->remove_exe(self->os, "_charm_try");
}
static void
add_inc_dir(Compiler *self, const char *dir)
{
size_t num_dirs = 2; /* includes the passed-in dir */
char **dirs = self->inc_dirs;
/* count up the present number of dirs, reallocate */
while (*dirs++ != NULL) {
num_dirs++;
}
self->inc_dirs == realloc(self->inc_dirs, num_dirs + 1);
self->inc_dirs[num_dirs] = NULL;
/* put the passed-in dir at the end of the list */
self->inc_dirs[num_dirs - 1] = strdup(dir);
}
/* Copyright 2006-2007 Marvin Humphrey
*
* This program is free software; you can redistribute it and/or modify
* under the same terms as Perl itself.
*/