/**********************************************************************
This file is part of Crack dot Com's free source code release of
Golgotha.
for
information about compiling & licensing issues visit this URL
If that doesn't help, contact Jonathan Clark at golgotha_source@usa.net (Subject should have "GOLG" in it) ***********************************************************************/ #include#include "i4_make.hh" #include #include "string.cc" #include "error.cc" #include "deps.cc" #include #include #ifdef __linux #include #include #define MKDIR(x) mkdir(x, 0xffff) #endif #ifdef _WINDOWS #include #include #include #define MKDIR(x) _mkdir(x) #endif #include "array_tree.hh" char *link_file="c:\\tmp\\link.lk"; mk_options_struct mk_options; enum {MAX_LEN=1000}; char abs_path[MAX_LEN]; int current_build_type=0; list failed_targets; list files_to_clean; list files_to_backup; #ifdef _WINDOWS int my_system (const char *command, int force=0) { char *argv[4]; if (current_build_type==BUILD_DEBUG || current_build_type==BUILD_OPT || current_build_type==BUILD_PROF || force) { if (command == 0) return 1; argv[0] = "command"; argv[1] = "/c"; argv[2] = (char *) command; argv[3] = 0; OSVERSIONINFO os; os.dwOSVersionInfoSize=sizeof(os); GetVersionEx(&os); if (os.dwPlatformId==VER_PLATFORM_WIN32_NT) return system(command); else return _spawnv(_P_WAIT, "c:\\windows\\command.com", argv); } return 0; } #else int my_system (const char *command, int force=0) { if (current_build_type==BUILD_DEBUG || current_build_type==BUILD_OPT || current_build_type==BUILD_PROF || force) { // warning- this breaks if you have a child process running already int pid, status; if (command == 0) return 1; pid = fork(); if (pid == -1) return -1; if (pid == 0) { char *argv[4]; argv[0] = "sh"; argv[1] = "-c"; argv[2] = (char*) command; argv[3] = 0; execv("/bin/sh", argv); exit(127); } do { wait(&status); return status; } while(1); } return 0; } #endif void extract(char *fn) { FILE *in=fopen(fn,"rb"); while (1) { unsigned char l,s1,s2,s3,s4; if (fread(&l,1,1,in)!=1) { fclose(in); exit(0); } char fn[256],buf[4096]; fread(fn, 1,l,in); FILE *out=fopen(fn,"wb"); if (!out) { for (int i=0; i sizeof(buf) ? sizeof(buf) :size; fread(buf, 1,rsize,in); fwrite(buf, 1, rsize, out); size-=rsize; } fclose(out); } else printf("extract: could not open %s for writing\n", fn); } } void mk_options_struct::get(int argc, char **argv) { int i; quiet=1; for (i=1; i BUF_SIZE) { buf=(char *)malloc(BUF_SIZE); boff=0; } memcpy(buf+boff,p,len); boff+=len; return buf+boff-len; } char *get_abs_path(char *filename, int force=0); void add_to_backup(char *fname) { char *full_name=get_abs_path(fname,1); // force a full name if (files_to_backup.find(full_name)==-1) files_to_backup.add(full_name); } void pcwd() { char buf[100]; getcwd(buf, 100); printf("cwd = %s\n",buf); } char start_path[256]; void set_abs_path(char *filename) { char tmp[MAX_LEN]; strcpy(tmp, filename); char *last_slash=0, *p=tmp, *q; for (; *p; p++) if (*p=='/' || *p=='\\') last_slash=p; if (last_slash) { last_slash[1]=0; strcpy(abs_path, get_abs_path(tmp)); if (mk_options.no_tmp) { chdir(start_path); chdir(abs_path); } } } char *get_abs_path(char *filename, int force) { if (mk_options.no_tmp && !force) return filename; else { char tmp[MAX_LEN]; strcpy(tmp, abs_path); char *s, *d; if ((filename[0]=='/' || filename[0]=='\\') || (filename[1]==':')) return filename; for (s=filename, d=tmp + strlen(tmp); *s; ) { if (s[0]=='.' && s[1]=='.' && (s[2]=='/' || s[2]=='\\')) { d-=2; while (*d!='/' && *d!='\\') { d--; if (d 4) { if (filename[l-3]=='.' && filename[l-2]=='r' && filename[l-1]=='c') ext_type=EXT_RC_RES; else if (filename[l-3]=='.' && filename[l-2]=='c' && filename[l-1]=='c') ext_type=EXT_O; else { printf("make_out_name : don't know what extension to use for %s",filename); exit(0); } } else { printf("make_out_name : filename to short : %s",filename); exit(0); } } if (mk_options.no_tmp) { d=tmp; char *start=filename; for (s=filename; *s && *s!='.'; s++); if (*s) { memcpy(d,filename, s-filename); d+=s-filename; } else { strcpy(d,filename); d+=strlen(d); } *d=0; } else { if (outdir) { strcpy(tmp,outdir); use_full_path=0; } else { if (mk_options.tmp_dir) sprintf(tmp,"%s%c", mk_options.tmp_dir, mk_options.slash_char); else { char *t=getenv("I4_TMP"); if (t) sprintf(tmp,"%s%c", t, mk_options.slash_char); else { if (mk_options.os==OS_LINUX) strcpy(tmp,"/tmp/"); else strcpy(tmp,"c:\\tmp\\"); } } } d=tmp+strlen(tmp); if (!use_full_path) { char *start=filename; for (s=filename; *s; s++) if (*s=='\\' || *s=='/' || *s==':') start=s+1; strcpy(d,start); d+=strlen(d); } else { for (s=filename; *s; s++) { if (*s=='\\' || *s=='/' || *s==':') { d[0]=d[1]='_'; d++; } else if (*s=='.') { d[0]='-'; } else *d=*s; d++; } } } if (current_build_type==BUILD_DEBUG) strcpy(d,"_debug"); else if (current_build_type==BUILD_OPT) strcpy(d,"_opt"); else if (current_build_type==BUILD_PROF) strcpy(d,"_prof"); else if (current_build_type==BUILD_CLEAN) strcpy(d,"_*"); d+=strlen(d); if (mk_options.os==OS_LINUX) { switch (ext_type) { case EXT_O : strcpy(d,".o"); break; case EXT_LIB : { if (mk_options.unix_libs_are_shared) strcpy(d,".so"); else strcpy(d,".a"); } break; case EXT_DEP : strcpy(d,".dep"); break; case EXT_PLUGIN: case EXT_DLL : strcpy(d,".dll"); break; case EXT_RAM_FILE : strcpy(d,".cc"); break; } } else { switch (ext_type) { case EXT_O : strcpy(d,".obj"); break; case EXT_LIB : strcpy(d,".lib"); break; case EXT_EXE : strcpy(d,".exe"); break; case EXT_DEP : strcpy(d,".dep"); break; case EXT_PDB : strcpy(d,".pdb"); break; case EXT_PCH : strcpy(d,".pch"); break; case EXT_PLUGIN: case EXT_DLL : strcpy(d,".dll"); break; case EXT_RAM_FILE : strcpy(d,".cc"); break; case EXT_RC_RES : strcpy(d,".res"); break; } } char *ret=buf_alloc(tmp, strlen(tmp)+1); if (current_build_type==BUILD_CLEAN) { char *full_name=get_abs_path(ret,1); // force a full name if (files_to_clean.find(full_name)==-1) files_to_clean.add(full_name); } return ret; } unsigned long check_sum32(void *buf, int buf_len) { unsigned char c1=0,c2=0,c3=0,c4=0; while (buf_len) { c1+=*((unsigned char *)buf); c2+=c1; buf=(void *)(((unsigned char *)buf)+1); c3+=c2; c4+=c3; buf_len--; } return (c1|(c2<<8)|(c3<<16)|(c4<<24)); } class mk_file_mod_node { public: int left, right; unsigned long checksum; unsigned long mod_time; int operator>(const mk_file_mod_node &b) const { return (checksum > b.checksum); } int operator<(const mk_file_mod_node &b) const { return (checksum < b.checksum); } mk_file_mod_node(unsigned long checksum) : checksum(checksum) {} mk_file_mod_node() {} }; i4_array_tree mod_tree; void set_mod_time(char *filename, int time_to_set) { mk_file_mod_node n(check_sum32(filename,strlen(filename))); int i=mod_tree.find(n); if (i!=-1) { mod_tree.get(i).mod_time=time_to_set; return ; } n.mod_time=time_to_set; mod_tree.add(n); } int get_mod_time(char *filename, int force_stat=0) { mk_file_mod_node n(check_sum32(filename,strlen(filename))); int i=mod_tree.find(n); if (i!=-1 && !force_stat) return mod_tree.get(i).mod_time; unsigned long t; #ifdef _WINDOWS struct _stat s; if (_stat(filename, &s)==0) t=s.st_mtime; else return 0; #elif __linux struct stat s; if (stat(filename, &s)==0) t=s.st_mtime; else return 0; #else #error define os here #endif if (i!=-1) mod_tree.get(i).mod_time=t; n.mod_time=t; mod_tree.add(n); return t; } enum { ALREADY_UP_TO_DATE, CHANGED, BUILD_ERROR, NO_MORE_TARGETS }; void clean_file(char *outname) { char cmd[200]; if (outname[strlen(outname)-1]!='*') { #ifdef _WINDOWS sprintf(cmd,"del %s", outname); #else sprintf(cmd,"rm %s", outname); #endif show_command(cmd,1); my_system(cmd, 1); } } int build_file(char *filename, mk_target_struct &target, mk_target_struct &top_target) { char *p=filename, *last_dot=0, cmd[MAX_LEN], inc[MAX_LEN], def[MAX_LEN]; inc[0]=0; def[0]=0; int i; for (p=filename; *p; p++) if (*p=='.' && p[1]!='.') last_dot=p; if (last_dot) { if (strcmp(last_dot,".cc")==0) { char *source_name=get_abs_path(filename); char *outname=make_out_name(source_name,EXT_O); if (failed_targets.find(outname)!=-1) return BUILD_ERROR; switch (current_build_type) { case BUILD_BACKUP: { add_to_backup(source_name); list *dep=get_deps(source_name, &target.inc); if (dep) { for (i=0; i size(); i++) add_to_backup((*dep)[i]); } } break; case BUILD_OPT : case BUILD_DEBUG : case BUILD_PROF : int rebuild=0; int m1=get_mod_time(outname); if (m1) { list *dep=get_deps(source_name, &target.inc); if (mk_options.show_includes && dep) { printf( "%s\n",filename); for (i=0; i size(); i++) printf( " %s\n",(*dep)[i]); } if (dep) { for (i=0; !rebuild && i size(); i++) { int src_mod_time=get_mod_time( (*dep)[i]); if (src_mod_time>m1) { if (mk_options.show_deps) printf( "%s newer than %s\n", (*dep)[i], outname); rebuild=1; } } } } else rebuild=1; if (rebuild) { if (mk_options.os==OS_LINUX) { for (i=0; i ltime) { if (mk_options.show_deps) printf( "%s newer than %s\n",oname, lname); object_files_have_changed=1; } d+=strlen(d); } } else { if (dll) sprintf(tmp, "link /MACHINE:IX86 /DEBUG /debugtype:coff /debugtype:both /DLL " "/nologo /PDB:%s /OUT:%s @%s%s", make_out_name(get_abs_path(lname), EXT_PDB, 0), lname, link_file, mk_options.quiet ? "> c:\\tmp\\null" : ""); else sprintf(tmp, "lib /nologo /OUT:%s @%s%s", lname, link_file, mk_options.quiet ? "> c:\\tmp\\null" : ""); FILE *fp=fopen(link_file, "wb"); for (i=0; i ltime) { if (mk_options.show_deps) printf( "%s newer than %s\n",oname, lname); object_files_have_changed=1; } } if (dll) { for (i=0; i ltime) { if (mk_options.show_deps) printf( "%s newer than %s\n",oname, lname); object_files_have_changed=1; } } if (target.def_file) sprintf(tmp+strlen(tmp), " /def:\"%s\"", target.def_file); } fclose(fp); } if (object_files_have_changed) { if (mk_options.quiet && (current_build_type!=BUILD_CLEAN && current_build_type!=BUILD_BACKUP)) printf("Creating library %s\n", target.target); else show_command(tmp); if (mk_options.no_compile) { set_mod_time(lname, 0x7fffffff); return CHANGED; } else { if (my_system(tmp)==0) { get_mod_time(lname, 1); // get time of output file // don't need to relink executable if using shared libraries if (mk_options.is_unix() && mk_options.unix_libs_are_shared) return ALREADY_UP_TO_DATE; return CHANGED; } else { failed_targets.add(lname); // don't try to build this again return BUILD_ERROR; } } } else return ALREADY_UP_TO_DATE; } int build_exe(int deps_have_changed, mk_target_struct &target) { char tmp[50000]; int i; char *ename=make_out_name(get_abs_path(target.target), EXT_EXE, 0, target.outdir); int etime=get_mod_time(ename); if (!etime) deps_have_changed=1; FILE *fp; if (mk_options.os==OS_LINUX) { char *sym_str=mk_options.no_syms ? "" : "-g "; sprintf(tmp, "g++ -rdynamic %s%s-o %s ", sym_str, current_build_type==BUILD_DEBUG ? "" : current_build_type==BUILD_OPT ? "-O2 " : "-O2 -pg ", ename); } else { sprintf(tmp, "link /SUBSYSTEM:%s /MACHINE:IX86 /DEBUG " "/NOLOGO /PDB:%s /NODEFAULTLIB /OUT:%s @%s", // /INCREMENTAL:NO target.app_type==WIN32_CONSOLE_APP ? "CONSOLE" : "WINDOWS", make_out_name(get_abs_path(target.target), EXT_PDB, 0), ename, link_file); fp=fopen(link_file,"wb"); if (!fp) mk_error("could not open %s for writing\n",link_file); } char *d=tmp+strlen(tmp); for (i=0; i etime) { if (mk_options.show_deps) printf( "%s newer than %s\n",oname, ename); deps_have_changed=1; } if (mk_options.os==OS_LINUX) sprintf(d, "%s ", oname); else fprintf(fp, "%s\n", oname); d+=strlen(d); } for (i=target.libs.size()-1; i>=0; i--) { if (mk_options.os==OS_LINUX) sprintf(d, "%s ", target.libs[i]); else fprintf(fp, "%s\n", target.libs[i]); if (!deps_have_changed && get_mod_time(target.libs[i])>etime) { if (mk_options.show_deps) printf( "%s newer than %s\n", target.libs[i], ename); deps_have_changed=1; } d+=strlen(d); } if (mk_options.os==OS_WIN32) fclose(fp); if (deps_have_changed) { if (current_build_type!=BUILD_CLEAN && current_build_type!=BUILD_BACKUP) { if (mk_options.quiet) printf("Linking %s\n", target.target); else printf("%s\n", tmp); } if (mk_options.no_compile) { set_mod_time(ename, 0x7fffffff); return CHANGED; } else { if (my_system(tmp)==0) { get_mod_time(ename, 1); // get time of output file return CHANGED; } else return BUILD_ERROR; } } else return ALREADY_UP_TO_DATE; } int build_target(mk_target_struct &target, mk_target_struct &top_target) // list &exe_src, // list &exe_inc, // list &exe_def, // list &lib_files, // list &dll_libs) { int i; int change=0; if (mk_options.targets_built.find(target.target)==-1) { mk_options.targets_built.add(target.target); if (strcmp(target.target_type,"list")==0) { for (i=0; i file && *d!='.') d--; if (strcmp(top_target.target_type,"plugin")==0) { if (strcmp(d,".def")==0) top_target.def_file=file; else if (strcmp(d,".a")==0 || (strstr(file, ".so")!=0) || strcmp(d,".lib")==0 || strcmp(d,".res")==0) { if (strcmp(d,".res")==0) add_to_backup(file); if (top_target.libs.find(file)==-1) top_target.libs.add(file); } else if (top_target.src.find(file)==-1) top_target.src.add(file); } } else if (strcmp(t, "add_to_executable")==0) { char *fn=get_token(p); char *file=get_abs_path(fn); char *d=file+strlen(file); while (d>file && *d!='.') d--; if (strcmp(top_target.target_type,"executable")==0 || strcmp(top_target.target_type,"plugin")==0) { if (strcmp(d,".def")==0) top_target.def_file=file; else if (strcmp(d,".a")==0 || (strstr(file, ".so")!=0) || strcmp(d,".lib")==0 || strcmp(d,".res")==0) { if (strcmp(d,".res")==0) add_to_backup(file); if (top_target.libs.find(file)==-1) top_target.libs.add(file); } else if (top_target.src.find(file)==-1) top_target.src.add(file); } } else if (strcmp(t,"backup")==0) { char *fname=get_token(p); add_to_backup(fname); } else if (strcmp(t,"add_include_directory")==0) { char *i=get_abs_path(get_token(p), 1); if (target.inc.find(i)==-1) target.inc.add(i); if (top_target.inc.find(i)==-1) top_target.inc.add(i); mk_debug("add_include_directory (dir=%s)\n", i); } else if (strcmp(t,"add_define")==0) { char *i=get_token(p); if (target.defines.find(i)==-1) target.defines.add(i); mk_debug("add_define (define=%s)\n", i); } else if (strcmp(t,"add_global_define")==0) { char *i=get_token(p); if (mk_global_defines.find(i)==-1) mk_global_defines.add(i); mk_debug("add_global_define (define=%s)\n", i); } else if (strcmp(t, "ram_file")==0) { char *in_name=get_token(p); int l=line_on; skip_white(p); if (current_build_type==BUILD_BACKUP) { add_to_backup(in_name); if (line_on==l) get_token(p); } else { if (line_on==l) build_ram_file(in_name, get_token(p), top_target); else build_ram_file(in_name, in_name, top_target); } } else if (strcmp(t, "use")==0) { t=get_token(p); char *use_file=0; if (strcmp(t,"file")==0) { if (strcmp(get_token(p),"=")) mk_error("expected = after file"); use_file=get_token(p); t=get_token(p); add_to_backup(use_file); } mk_debug("use (file=%s) (target=%s)\n", use_file, t); mk_target_struct tar; int cur_line=line_on; // save current line & file info char *cur_file=file_on; char *cur_contents=file_contents; char old_abs[MAX_LEN]; char *f; if (use_file) { f=load_file(use_file, 1); if (!f) mk_error("could not load project file '%s'", use_file); strcpy(old_abs, abs_path); set_abs_path(use_file); } else f=file_contents; if (get_target(tar, top_target, f,t)==NO_MORE_TARGETS) mk_error("could not find target '%s'", t); // add include paths to local target for (int i=0; i >24; s2=(size&0xff0000)>>16; s3=(size&0xff00)>>8; s4=(size&0xff)>>0; fwrite(&s1, 1,1, out); fwrite(&s2, 1,1, out); fwrite(&s3, 1,1, out); fwrite(&s4, 1,1, out); char buf[4096]; int rsize=0; do { rsize=fread(buf, 1, 4096, in); fwrite(buf, rsize, 1, out); } while (rsize); t_files++; fclose(in); } else printf("backup: couldn't open %s\n", files_to_backup[i]); } fclose(out); printf("backed up %d files to backup.i4\n", t_files); } else printf("backup: couldn't backup.i4 for writing\n"); } } int i4_make_main(int argc, char **argv) { setbuf(stdout, 0); #ifdef _WINDOWS mk_options.os=OS_WIN32; _getcwd(abs_path, sizeof(abs_path)); #elif __linux mk_options.os=OS_LINUX; getcwd(abs_path, sizeof(abs_path)); #else #error add new os here #endif strcat(abs_path, "/"); mk_options.get(argc, argv); char *file_start=load_file(mk_options.project_file, 1), *b; if (!file_start) mk_error("Project file not found : '%s'", mk_options.project_file); mk_target_struct target; getcwd(start_path, 256); for (current_build_type=1; current_build_type<=BUILD_LAST; current_build_type*=2) { if (mk_options.build_flags & current_build_type) { if (current_build_type==BUILD_BACKUP) add_to_backup(mk_options.project_file); if (!mk_options.targets_to_build.size()) { b=file_start; int ret; while (ret=get_target(target, target, b)!=NO_MORE_TARGETS) { if (build_target(target, target)==BUILD_ERROR) if (!mk_options.continue_on_error) { perror("Stopping : "); exit(-1); } target.reset(); mk_options.targets_built.clear(); } } for (int i=0; i