Author: arty Date: Fri Jan 5 08:56:26 2007 New Revision: 25303
URL: http://svn.reactos.org/svn/reactos?rev=25303&view=rev Log: Compiler driver wrapper for building pe-powerpcle executables. Expects access to a powerpc gcc and ld, as well as alink. The scripts in here are transformed by sed ala GNU configure.
fork_win32 and fork_unix provide a uniform way of calling an external program and reading stderr.
dlltool.cpp is a minimalist what-if about replacing binutils' dlltool. It's not used by might be instructive.
Added: branches/powerpc/reactos/tools/ppc-build/compdvr/ branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-dlltool.in (with props) branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-gcc.in branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-ld.in branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-windres.in branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr.cpp branches/powerpc/reactos/tools/ppc-build/compdvr/dlltool.cpp branches/powerpc/reactos/tools/ppc-build/compdvr/fork_execvp.h (with props) branches/powerpc/reactos/tools/ppc-build/compdvr/fork_unix.cpp (with props) branches/powerpc/reactos/tools/ppc-build/compdvr/fork_win32.cpp (with props)
Added: branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-dlltool.in URL: http://svn.reactos.org/svn/reactos/branches/powerpc/reactos/tools/ppc-build/... ============================================================================== --- branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-dlltool.in (added) +++ branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-dlltool.in Fri Jan 5 08:56:26 2007 @@ -1,0 +1,7 @@ +#!/bin/sh + +DIR=@PREFIX@ +BPREFIX=@BPREFIX@ +TARGET=@TARGET@ + +${BPREFIX}dlltool -S $DIR/bin/${TARGET}as -L $DIR/bin/${TARGET}ld $*
Propchange: branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-dlltool.in ------------------------------------------------------------------------------ svn:executable = *
Added: branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-gcc.in URL: http://svn.reactos.org/svn/reactos/branches/powerpc/reactos/tools/ppc-build/... ============================================================================== --- branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-gcc.in (added) +++ branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-gcc.in Fri Jan 5 08:56:26 2007 @@ -1,0 +1,60 @@ +#!/bin/sh + +DIR=@PREFIX@ +CPREFIX=@CPREFIX@ +TARGET=@TARGET@ + +if [ "x$*" = "x-v" ] ; then + exec ${CPREFIX}gcc -v +fi + +includes="-isystem $DIR/lib/mingw-crt-headers -isystem $DIR/lib/gcc-core-headers" + +argstr="" +for arg in $* ; do + if [ x"$arg" = x-mingw ] ; then + argstr="$argstr -isystem $DIR/lib/windows-headers" + else + argstr="$argstr $arg" + fi +done + +TEMP=`mktemp -d` +export TEMP +if [ ! -d $TEMP ] ; then + echo "Could not make temp dir $TEMP" + exit 1 +fi +TMP=$TEMP + +`dirname $0`/${TARGET}driver-gcc \ + -mlittle \ + -nostdinc \ + -D__cdecl__= \ + -D__stdcall__= \ + -D__fastcall__= \ + -D__declspec(x)= \ + -D__cdecl= \ + -D__stdcall= \ + -D__fastcall= \ + -Dcdecl= \ + -Dstdcall= \ + -Dfastcall= \ + -Ddllimport= \ + -Ddllexport= \ + -Du_short=unsigned\ short \ + -Du_long=unsigned\ long \ + -Du_int=unsigned\ int \ + -Du_char=unsigned\ char \ + -ldscript ${DIR}/lib/ldscript \ + -gcc-name ${CPREFIX}gcc \ + -link-stage-name ${DIR}/bin/${TARGET}ld \ + -extra-link-stage $DIR/bin/alink.exe \ + -mingw-lib-dir $DIR/lib \ + $includes \ + $argstr </dev/null + +RES=$? + +rm -rf $TEMP +exit $RES
Added: branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-ld.in URL: http://svn.reactos.org/svn/reactos/branches/powerpc/reactos/tools/ppc-build/... ============================================================================== --- branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-ld.in (added) +++ branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-ld.in Fri Jan 5 08:56:26 2007 @@ -1,0 +1,30 @@ +#!/bin/sh + +DIR=@PREFIX@ +BPREFIX=@BPREFIX@ +TARGET=@TARGET@ + +if [ "x$*" = x-v ] ; then + exec ${BPREFIX}ld -v +fi + +TEMP=`mktemp -d` +export TEMP +if [ ! -d $TEMP ] ; then + echo "Could not make temp dir $TEMP" + exit 1 +fi +TMP=$TEMP + +`dirname $0`/${TARGET}driver-ld \ + -EL \ + -ldscript ${DIR}/lib/ldscript \ + -mingw-lib-dir ${DIR}/lib \ + -link-stage-name ${BPREFIX}ld \ + -extra-link-stage $DIR/bin/alink.exe \ + $* + +RES=$? + +rm -rf $TEMP +exit $RES
Added: branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-windres.in URL: http://svn.reactos.org/svn/reactos/branches/powerpc/reactos/tools/ppc-build/... ============================================================================== --- branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-windres.in (added) +++ branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr-windres.in Fri Jan 5 08:56:26 2007 @@ -1,0 +1,7 @@ +#!/bin/sh + +DIR=@PREFIX@ +BPREFIX=@BPREFIX@ +TARGET=@TARGET@ + +exec ${BPREFIX}windres -F elf32-powerpcle $*
Added: branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr.cpp URL: http://svn.reactos.org/svn/reactos/branches/powerpc/reactos/tools/ppc-build/... ============================================================================== --- branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr.cpp (added) +++ branches/powerpc/reactos/tools/ppc-build/compdvr/compdvr.cpp Fri Jan 5 08:56:26 2007 @@ -1,0 +1,363 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <list> +#include <string> +#include <vector> +#include <sstream> +#include <algorithm> +#include "fork_execvp.h" + +/* tool for transforming gcc -### output and using it to drive the compiler + * elements ourselves. Most importantly, we need to know what file gcc asks + * the linker to input and output, and add an intermediate stage with alink. + */ + +typedef enum { empty, found_q, found_bs } break_t; + +template <class T> +T break_arguments( const std::string &line ) { + break_t state = empty; + T args; + std::string arg; + + for( size_t i = 0; i < line.size(); i++ ) { + switch( state ) { + case empty: + if( line[i] == '"' ) { + state = found_q; + } + break; + + case found_q: + if( line[i] == '\' ) state = found_bs; + else if( line[i] == '"' ) { + state = empty; + args.push_back(arg); + arg = ""; + } else arg += line[i]; + break; + + case found_bs: + state = found_q; + arg += line[i]; + break; + } + } + + return args; +} + +template <class T> +std::vector<char *> get_arg_ptrs +( const T &arg_strings ) { + std::vector<char *> arg_out; + for( size_t i = 0; i < arg_strings.size(); i++ ) + arg_out.push_back( (char *)arg_strings[i].c_str() ); + arg_out.push_back(0); + return arg_out; +} + +int execute_command( bool verbose, const std::vectorstd::string &args ) { + std::string error; + std::vector<char *> args_ptrs; + const char *tag = "executable"; + + if( verbose ) { + fprintf( stderr, "<command>\n" ); + for( size_t i = 0; i < args.size(); i++ ) { + fprintf( stderr, "<%s>%s</%s>\n", tag, args[i].c_str(), tag ); + tag = "argument"; + } + } + + Process p = fork_execvp( args ); + + while( p && p->ProcessStarted() && !p->EndOfStream() ) + fprintf( stderr, "%s", p->ReadStdError().c_str() ); + + if( verbose ) { + fprintf( stderr, "<status>%d</status>\n", p->GetStatus() ); + fprintf( stderr, "</command>\n" ); + } + + return p ? p->GetStatus() : -1; +} + +std::string make_tmp_name() { + int fd; + std::string name; + + while( true ) { + name = tmpnam(NULL); + name += ".obj"; + if( (fd = creat( name.c_str(), 0644 )) != -1 ) { + close(fd); + return name; + } + } +} + +void recognize_arg( std::vectorstd::string &args, + std::string &result, + size_t &i, + const std::string &argname, + const std::string &short_argname = "" ) { + if( (short_argname.size() && (args[i] == short_argname)) || + (args[i] == argname) ) { + result = args[i+1]; + args.erase(args.begin()+i); + args.erase(args.begin()+i--); + } else if( args[i].substr(0,argname.size()+1) == argname + "=" ) { + result = args[i].substr(argname.size()+1); + args.erase(args.begin()+i--); + } +} + +int run_ld( bool verbose, bool nostdlib, bool nostartfiles, bool is_dll, + bool make_map, + const std::string &lib_dir, + const std::string &extra_linker_stage, + const std::string &ldscript, + const std::vectorstd::string &arg_vect ) { + bool use_libgcc = false; + std::vectorstd::string args = arg_vect; + std::string temp_name = make_tmp_name(), real_output, + entry_point, image_base, subsystem = "windows", + make_dll, file_align, section_align, base_file; + std::vectorstd::string::iterator i = + std::find(args.begin(),args.end(),"-lgcc"); + + if( i != args.end() ) { + args.erase( i ); + use_libgcc = true; + } + + if( !nostartfiles ) { + if( make_dll.size() ) + args.push_back(lib_dir + "/dllcrt2.o"); + else + args.push_back(lib_dir + "/crt2.o"); + } + + if( !nostdlib ) { + args.push_back(std::string("-L") + lib_dir); + args.push_back("-lkernel32"); + args.push_back("-lmsvcrt"); + args.push_back("-lcrtdll"); + args.push_back("-lmingw32"); + } + if( use_libgcc ) + args.push_back(lib_dir + "/libgcc.a"); + + if( verbose ) + args.insert(args.begin()+1,"-v"); + + args.insert(args.begin()+1,"-T"); + args.insert(args.begin()+2,ldscript); + args.insert(args.begin()+1,"-r"); + args.insert(args.begin()+1,"--start-group"); + args.push_back("--end-group"); + + for( size_t i = 0; i < args.size(); i++ ) { + if( args[i] == "-o" && i < args.size()-1 ) { + real_output = args[++i]; + args[i] = temp_name; + } else if( args[i].substr(0,4) == "-mdll" ) { + args.erase(args.begin()+i--); + make_dll = "-dll"; + } + + recognize_arg( args, entry_point, i, "--entry", "-e" ); + recognize_arg( args, image_base, i, "--image-base" ); + recognize_arg( args, subsystem, i, "--subsystem" ); + recognize_arg( args, file_align, i, "--file-alignment" ); + recognize_arg( args, section_align, i, "--section-alignment" ); + recognize_arg( args, base_file, i, "--base-file" ); + } + + if( execute_command( verbose, args ) ) + return 1; + + if( base_file.size() ) { + FILE *f = fopen(base_file.c_str(), "wb"); + if( !f ) { + fprintf(stderr, "<error>\n"); + perror(base_file.c_str()); + fprintf(stderr, "</error>\n"); + return 1; + } + fclose(f); + } + + args.clear(); + args.push_back( extra_linker_stage ); + if(make_map) + args.push_back("-m+"); + args.push_back( "-oPE" ); + args.push_back( "-o" ); + args.push_back( real_output ); + args.push_back( "-subsys" ); + args.push_back( subsystem ); + + if( entry_point.size() ) { + size_t at = 0; + args.push_back("-entry"); + // Entry points will be specified with leading '_', probably + if( entry_point[0] == '_' ) + entry_point = entry_point.substr(1); + at = entry_point.find('@'); + if( at != std::string::npos ) + entry_point = entry_point.substr(0,at); + args.push_back(entry_point); + } + + if( image_base.size() ) { + args.push_back("-base"); + args.push_back(image_base); + } + + if( file_align.size() ) { + args.push_back("-filealign"); + args.push_back(file_align); + } + + if( section_align.size() ) { + args.push_back("-objectalign"); + args.push_back(section_align); + } + + if( make_dll.size() ) { + args.push_back(make_dll); + } + + if( real_output.size() ) { + args.push_back( temp_name ); + int res = execute_command( verbose, args ); + unlink( temp_name.c_str() ); + return res; + } else return 0; +} + +int main( int argc, char **argv ) { + bool verbose = false, ld_mode = false, nostdlib = false, + nostartfiles = false, is_dll = false, make_map = false; + int err_fd[2], read_len, child_pid_gcc, child_pid_command, status = 0; + std::string gcc_name, gcc_hash_output, gcc_line, linker_name = "ld", + mingw_lib_dir, ldscript; + std::string extra_linker_stage; + std::vectorstd::string gcc_args_str, + subcmd_args; + std::vector<char *> arguments_for_gcc; + char buf[1024]; + + for( int i = 1; i < argc; i++ ) { + if( std::string("-gcc-name") == argv[i] && i < argc-1 ) { + gcc_name = argv[++i]; + } else if( std::string("-ldscript") == argv[i] && i < argc-1 ) { + ldscript = argv[++i]; + } else if( std::string("-link-stage-name") == argv[i] && i < argc-1 ) { + linker_name = argv[++i]; + } else if( std::string("-extra-link-stage") == argv[i] && i < argc-1 ) { + extra_linker_stage = argv[++i]; + } else if( std::string("-mingw-lib-dir") == argv[i] && i < argc-1 ) { + mingw_lib_dir = argv[++i]; + } else if( std::string("-v") == argv[i] ) { + verbose = true; + } else if( std::string("-pipe") == argv[i] ) { + /* ignore */ + } else if( std::string("-T") == argv[i] ) { + /* ignore */ + i++; + } else if( std::string("-nostdlib") == argv[i] ) { + nostdlib = true; + } else if( std::string("-nostartfiles") == argv[i] ) { + nostartfiles = true; + } else if( std::string("-shared") == argv[i] ) { + is_dll = true; + } else if( std::string("-map") == argv[i] ) { + make_map = true; + } else { + gcc_args_str.push_back(argv[i]); + } + } + + /* We never use the system start files or standard libs */ + gcc_args_str.insert(gcc_args_str.begin()+1,"-nostdlib"); + gcc_args_str.insert(gcc_args_str.begin()+1,"-nostartfiles"); + + if( std::string(argv[0]).find("ld") != std::string::npos ) { + gcc_args_str.insert + ( gcc_args_str.begin(), linker_name ); + return run_ld + ( verbose, nostdlib, nostartfiles, is_dll, make_map, mingw_lib_dir, + extra_linker_stage, ldscript, gcc_args_str ); + } + if( verbose ) fprintf( stderr, "<compiler-driver>\n" ); + + // Stack on driver name and dump commands flag + gcc_args_str.insert(gcc_args_str.begin(),std::string("-###")); + gcc_args_str.insert(gcc_args_str.begin(),gcc_name); + + /* Redirect stderr to our pipe */ + if( verbose ) { + const char *tag = "executable"; + fprintf( stderr, "<gcc>\n" ); + for( size_t i = 0; i < gcc_args_str.size(); i++ ) { + fprintf( stderr, " <%s>%s</%s>\n", + tag, gcc_args_str[i].c_str(), + tag ); + tag = "arg"; + } + fprintf( stderr, "</gcc>\n" ); + } + + Process p = fork_execvp( gcc_args_str ); + + while( p && p->ProcessStarted() && !p->EndOfStream() ) + gcc_hash_output += p->ReadStdError(); + + std::istringstream iss( gcc_hash_output ); + + if( p->GetStatus() ) goto final; + + while( std::getline( iss, gcc_line, '\n' ) ) { + // command line + if( gcc_line.size() > 2 && gcc_line[0] == ' ' ) { + subcmd_args = + break_arguments<std::vectorstd::string >( gcc_line ); + + if( subcmd_args.size() < 1 ) continue; + + if( subcmd_args[0].find("collect2") != std::string::npos || + subcmd_args[0].find("ld") != std::string::npos ) { + if( run_ld( verbose, nostdlib, nostartfiles, is_dll, make_map, + mingw_lib_dir, extra_linker_stage, ldscript, + subcmd_args ) ) + goto final; + else + continue; + } + + if( verbose ) + subcmd_args.insert(subcmd_args.begin()+1,"-v"); + + if( execute_command + ( verbose, subcmd_args ) ) + goto final; + } else if( verbose ) + fprintf( stderr, "<error>%s</error>\n", gcc_line.c_str() ); + } + goto theend; + + final: + status = 1; + + theend: + if( verbose ) { + fprintf( stderr, "<status>%d</status>\n", status ); + fprintf( stderr, "</compiler-driver>\n" ); + } + return status; +}
Added: branches/powerpc/reactos/tools/ppc-build/compdvr/dlltool.cpp URL: http://svn.reactos.org/svn/reactos/branches/powerpc/reactos/tools/ppc-build/... ============================================================================== --- branches/powerpc/reactos/tools/ppc-build/compdvr/dlltool.cpp (added) +++ branches/powerpc/reactos/tools/ppc-build/compdvr/dlltool.cpp Fri Jan 5 08:56:26 2007 @@ -1,0 +1,566 @@ +#include <stdio.h> +#include <ctype.h> +#include <map> +#include <vector> +#include <string> +#include <sstream> +#include <fstream> + +/* + * .idata$2_liba_dll # liba import directory + * __dll_liba_import_directory: + * .rva __dll_tail + * .long 0 + * .long 0 + * .rva __liba_dll_name + * .rva __liba_dll_fthunk + * .idata$2_libb_dll # libb import directory + * __dll_libb_import_directory: + * 20 bytes ... + * .idata$3 # Zero entry + * __dll_tail: + * 20 zeroes ... + * .idata$4_liba_dll # Import Lookup Table + * __dll_liba_ilt: + * .idata$4_liba_fun1_ilt + * __dll_liba_fun1_ilt: + * .rva __dll_liba_fun1_hint + * .idata$4_liba_fun2_ilt + * __dll_libb_fun2_ilt: + * .rva __dll_liba_fun1_hint + * .idata$4_libb_dll # Import Lookup Table + * .idata$5_libb_fun1_ilt + * .idata$5_libb_fun2_ilt + * .idata$5_liba_dll # Import Address Table + * .idata$5_liba_fun1_iat + * __dll_liba_fun1_ia: + * .long 0 + * .idata$5_liba_fun2_iat + * .idata$5_libb_dll # Import Address Table + * .idata$5_libb_fun1_iat + * .idata$5_libb_fun2_iat + * .idata$6_liba_dll # Hint Table + * .idata$6_liba_fun1_hint + * .idata$6_liba_fun2_hint + * .idata$6_libb_dll # Hint Table + * .idata$6_liba_fun1_hint + * .idata$6_liba_fun2_hint + * .idata$7_liba_dll # DLL Name + * __liba_dll_name: + * .asciz "liba.dll" + * .idata$7_libb_dll # DLL Name + * __libb_dll_name: + * .asciz "libb.dll" + * + */ + +std::string uppercase( const std::string &mcase ) { + std::string out; + for( std::string::const_iterator i = mcase.begin(); + i != mcase.end(); + i++ ) { + out += toupper(*i); + } + return out; +} + +std::string comment_strip( const std::string &line ) { + size_t s = line.find(';'); + if( s != std::string::npos ) return line.substr(0,s); + else return line; +} + +class DefFile { +public: + class Export { + public: + Export( const std::string &name, const std::string &alias = "", + int ordinal = -1 ) : + name(name), alias_of(alias), ordinal(ordinal) {} + + const std::string &getName() const { return name; } + const std::string &getAliasOf() const { return alias_of; } + int getOrdinal() const { return ordinal; } + + private: + std::string name; + std::string alias_of; + int ordinal; + }; + + DefFile() : ordbase(1), mode(0) { } + + static std::string clean_for_symbol( const std::string &s ) { + std::string out; + + for( size_t i = 0; i < s.size(); i++ ) { + out += isalpha(s[i]) ? s[i] : '_'; + } + + return out; + } + + static std::string section( const std::string &name ) { + return std::string("\t.section\t") + name + "\n"; + } + + static std::string symbol( const std::string &name ) { + return name + ":\n"; + } + + static std::string global( const std::string &name ) { + return std::string("\t.global\t") + name + "\n"; + } + + static std::string global_sym( const std::string &name ) { + return global(name) + symbol(name); + } + + static std::string impsym( const std::string &name, size_t i ) { + std::ostringstream oss; + oss << name << "_" << i; + return oss.str(); + } + + std::string archive_deco( const std::string &sym ) { + return std::string("__dll_archive_") + libsym + "_" + sym; + } + + static std::string rva( const std::string &symbol ) { + return std::string("\t.rva\t") + symbol + "\n"; + } + + std::string common_name( size_t i, const std::string &_name = "" ) const { + size_t at; + std::string name = _name; + + if( !name.size() ) name = exports[i].getName(); + if( !name.size() ) { + std::ostringstream oss; + oss << libsym << "_ordinal_" << i; + return oss.str(); + } + + if( name[0] == '@' ) name = name.substr(1); + at = name.find('@'); + if( at != std::string::npos ) + name = name.substr(0,at); + + return name; + } + + size_t count_names() const { + size_t res = 0; + for( size_t i = 0; i < exports.size(); i++ ) + if( exports[i].getName().size() ) ++res; + return res; + } + + bool parse( int ln, const std::string &line ) { + std::string command; + std::string stripped_line = comment_strip(line); + + std::istringstream iss(stripped_line); + + bool got_word = iss >> command; + + if( uppercase(command) == "LIBRARY" ) { + if( mode ) { + fprintf( stderr, "Got library out of turn on line %d\n", ln ); + return false; + } + mode++; + iss >> libname; + libsym = clean_for_symbol(libname); + import_directory_entry = archive_deco("import_directory_entry"); + import_directory_term = archive_deco("import_directory_term"); + dll_name_text = archive_deco("dll_name"); + original_first_thunk = archive_deco("ofirst_thk"); + original_first_thunk_term = original_first_thunk + "_term"; + first_thunk = archive_deco("first_thk"); + first_thunk_term = first_thunk + "_term"; + import_desc_table = archive_deco("import_desc"); + } else if( uppercase(command) == "EXPORTS" ) { + if( !mode ) { + fprintf( stderr, "Got exports out of turn on line %d\n", ln ); + return false; + } + mode++; + } else if( got_word ) { + size_t equal, at; + std::string name, alias, name_alias, ordinal_maybe; + int ordinal = -1; + + if( mode != 2 ) { + fprintf( stderr, "Got extraneous input on line %d\n", ln ); + return false; + } + + name_alias = command; + if( iss >> ordinal_maybe ) + ordinal = atoi(ordinal_maybe.substr(1).c_str()); + + equal = name_alias.find('='); + if( equal == std::string::npos ) { + name = name_alias; + } else { + name = name_alias.substr(0,equal); + equal++; + alias = name_alias.substr(equal); + } + + if( kill_at ) { + at = name.find('@'); + if( at != std::string::npos ) + name = name.substr(0,at); + at = alias.find('@'); + if( at != std::string::npos ) + alias = alias.substr(0,at); + } + + Export ex(name,alias,ordinal); + + export_byname.insert( std::make_pair(name, exports.size()) ); + exports.push_back(ex); + } + + return true; + } + + std::string makeExportData() const { + std::ostringstream oss; + + oss << section(".edata") + << longdata(0) + << longdata(time(NULL)) + << longdata(0) + << rva(libsym) + << longdata(ordbase) + << longdata(exports.size()) + << longdata(count_names()) + << rva("exported_functions") + << rva("exported_names") + << rva("exported_ordinals") + << global_sym(libsym) + << asciz(libname) + << align(4) + << symbol("exported_functions"); + + for( size_t i = 0; i < exports.size(); i++ ) { + oss << "\t.rva\t" << common_name(i) << "\n"; + } + + oss << "exported_ordinals:\n"; + int lastord = ordbase; + for( size_t i = 0; i < exports.size(); i++ ) { + if( exports[i].getOrdinal() != -1 ) + lastord = exports[i].getOrdinal(); + else + lastord++; + oss << "\t.short\t" << lastord << "\n"; + } + + oss << "exported_names:\n"; + + for( size_t i = 0; i < exports.size(); i++ ) { + if( exports[i].getName().size() ) { + oss << "\t.rva\texport_name_" << (int)i << "\n"; + } + } + + for( size_t i = 0; i < exports.size(); i++ ) { + if( exports[i].getName().size() ) { + oss << "export_name_" << (int)i + << ":\t.asciz\t"" + << exports[i].getName() << ""\n"; + } + } + + oss << "# End of exports\n"; + + return oss.str(); + } + + static std::string align(int n) { + std::ostringstream oss; + oss << "\t.align\t" << n << "\n"; + return oss.str(); + } + + static std::string longdata(long l) { + std::ostringstream oss; + oss << "\t.long\t" << l << "\n"; + return oss.str(); + } + + static std::string shortdata(int i) { + std::ostringstream oss; + oss << "\t.short\t" << i << "\n"; + return oss.str(); + } + + static std::string space(int s) { + std::ostringstream oss; + oss << "\t.space\t" << s << "\n"; + return oss.str(); + } + + static std::string asciz(const std::string &s) { + std::string quote = """; + if(s.size() && s[0] == '"') + quote = ""; + return std::string("\t.asciz\t") + quote + s + quote + "\n"; + } + + std::string makeArchiveHeader() const { + std::ostringstream oss; + + oss << section(".idata$2") + << global_sym(import_directory_entry) + << rva(original_first_thunk) + << longdata(0) + << longdata(0) + << rva(dll_name_text) + << section(".idata$4") + << global_sym(original_first_thunk) + << section(".idata$5") + << global_sym(first_thunk) + << section(".idata$6") + << global_sym(import_desc_table); + + return oss.str(); + } + + std::string makeArchiveFooter() const { + std::ostringstream oss; + + oss << section(".idata$3") + << global_sym(import_directory_term) + << space(20) + << global_sym(original_first_thunk_term) + << longdata(0) + << global_sym(first_thunk_term) + << longdata(0) + << section(".idata$7") + << global_sym(dll_name_text) + << asciz(libname); + + return oss.str(); + } + + std::string makePerImportData( size_t i ) const { + std::ostringstream oss; + + oss << section(".text") + << global_sym(common_name(i)) + << "\taddi\t1,1,16\n" + << "\tmflr\t0\n" + << "\tstw\t0,0(1)\n" + << "\tlis\t0," << impsym(first_thunk,i) << "@ha\n" + << "\tori\t0,0," << impsym(first_thunk,i) << "@l\n" + << "\tlwz\t0," << (4 * i) << "(0)\n" + << "\tmtlr\t0\n" + << "\tblrl\n" + << "\tlwz\t0,0(1)\n" + << "\taddi\t1,1,-16\n" + << "\tblr\n" + << rva(impsym(original_first_thunk,i)) + << rva(impsym(import_desc_table,i)) + << rva(impsym(first_thunk,i)) + << rva(import_directory_entry) + << rva(import_directory_term) + << section(".idata$4") + << symbol(impsym(original_first_thunk,i)) + << rva(impsym(import_desc_table,i)) + << section(".idata$5") + << symbol(impsym(import_desc_table,i)) + << shortdata(exports[i].getOrdinal()) + << asciz(exports[i].getName()) + << section(".idata$6") + << symbol(impsym(first_thunk,i)) + << rva(impsym(import_desc_table,i)); + + return oss.str(); + } + + size_t numFunctions() const { return exports.size(); } + + void setKillAt( bool kill ) { kill_at = kill; } + +private: + bool kill_at; + std::string libname, libsym; + std::string import_directory_entry, import_directory_term; + std::string original_first_thunk, first_thunk, dll_name_text; + std::string original_first_thunk_term, first_thunk_term; + std::string import_desc_table; + std::vector<Export> exports; + std::mapstd::string,size_t export_byname; + int ordbase, mode; +}; + +std::string maketemp +( const std::string &prefix, + const std::string &suffix, + const std::string &payload ) { + std::string template_accum = + std::string("/tmp/") + prefix + "XXXXXX"; + std::vector<char> storage, duplicate; + + for( size_t i = 0; i < template_accum.size(); i++ ) + storage.push_back(template_accum[i]); + storage.push_back(0); + + duplicate = storage; + std::string result; + mktemp(&duplicate[0]); + result = &duplicate[0]; + result += suffix; + std::ofstream of; + of.open(result.c_str()); + of << payload; + of.close(); + + return result; +} + +void _check( const std::string &varname, const std::string &varval ) { + if( !varval.size() ) { + fprintf( stderr, "You must specify %s\n", varname.c_str() ); + exit(1); + } +} + +#define check(x) _check(#x,x) + +bool parseArg(int argc, char **argv, + std::string &argval, + const char *short_n, + const char *long_n = 0, + const char *extra_n = 0) +{ + std::string argv_i; + bool got_val = false; + + if( !long_n ) { long_n = short_n; } + + for( int i = 0; i < argc; i++ ) { + argv_i = argv[i]; + if( argv_i == short_n ) { + if( i < argc-1 ) + argval = argv[i+1]; + got_val = true; + } else if( argv_i == long_n ) { + if( i < argc-1 ) + argval = argv[i+1]; + got_val = true; + } else if( argv_i.substr(0,strlen(long_n)+1) == + std::string(long_n) + "=" ) { + argval = argv_i.substr(strlen(long_n)+1); + got_val = true; + } + } + + if( !got_val && extra_n ) + return parseArg(argc,argv,argval,short_n,extra_n); + + return got_val; +} + +int main( int argc, char **argv ) { + int i, ln = 0; + bool dont_delete = false, kill_at = false; + DefFile f; + std::string line; + std::string def_file, exp_file, dll_name, imp_name, + as_name = "as", ar_name = "ar cq", foo; + std::ifstream in_def; + + parseArg(argc,argv,def_file,"-d","--def","--input-def"); + parseArg(argc,argv,exp_file,"-e","--exp","--output-exp"); + parseArg(argc,argv,imp_name,"-l","--lib","--output-lib"); + parseArg(argc,argv,dll_name,"-D","--dll","--dll-name"); + parseArg(argc,argv,as_name, "-S","--as"); + dont_delete = parseArg(argc,argv,foo,"-n"); + kill_at = parseArg(argc,argv,foo,"-k"); + + check(def_file); + check(imp_name); + + int err = 0; + std::string export_file, archive_header_file, archive_footer_file; + std::vectorstd::string archive_member_files; + std::ostringstream make_exp; + std::ostringstream make_lib, archive_it; + + f.setKillAt(kill_at); + + in_def.open(def_file.c_str()); + while( std::getline(in_def,line) ) + if(!f.parse(++ln,line)) { + fprintf( stderr, "Ungrammatic def file\n" ); + goto cleanup; + } + in_def.close(); + + unlink(imp_name.c_str()); + + export_file = maketemp("exports",".s",f.makeExportData()); + archive_header_file = maketemp("arch_hdr",".s",f.makeArchiveHeader()); + archive_footer_file = maketemp("arch_end",".s",f.makeArchiveFooter()); + for( size_t i = 0; i < f.numFunctions(); i++ ) + archive_member_files.push_back + (maketemp("arch_mem",".s",f.makePerImportData(i))); + + if( exp_file.size() ) { + make_exp << as_name << " -mlittle -o " << exp_file << " " << export_file; + + fprintf( stderr, "execute %s\n", make_exp.str().c_str() ); + + if( (err = system(make_exp.str().c_str())) ) { + fprintf(stderr, "Failed to execute %s\n", make_exp.str().c_str()); + goto cleanup; + } + } + + make_lib << as_name << " -mlittle -o " << archive_header_file << ".o " + << archive_header_file + << " && " + << as_name << " -mlittle -o " << archive_footer_file << ".o " + << archive_footer_file; + + archive_it << ar_name << " " << imp_name << " " + << archive_header_file << ".o"; + for( size_t i = 0; i < f.numFunctions(); i++ ) { + make_lib << " && " + << as_name << " -mlittle -o " + << archive_member_files[i] << ".o " + << archive_member_files[i]; + archive_it << " " << archive_member_files[i] << ".o"; + } + + archive_it << " " << archive_footer_file << ".o"; + make_lib << " && " << archive_it.str(); + + fprintf( stderr, "execute %s\n", make_lib.str().c_str() ); + + if( (err = system(make_lib.str().c_str())) ) { + fprintf(stderr, "Failed to execute %s\n", make_exp.str().c_str()); + goto cleanup; + } + +cleanup: + if( !dont_delete ) { + unlink(export_file.c_str()); + unlink(archive_header_file.c_str()); + unlink((archive_header_file + ".o").c_str()); + unlink(archive_footer_file.c_str()); + unlink((archive_footer_file + ".o").c_str()); + for( size_t i = 0; i < f.numFunctions(); i++ ) { + unlink(archive_member_files[i].c_str()); + unlink((archive_member_files[i] + ".o").c_str()); + } + } + + return err; +}
Added: branches/powerpc/reactos/tools/ppc-build/compdvr/fork_execvp.h URL: http://svn.reactos.org/svn/reactos/branches/powerpc/reactos/tools/ppc-build/... ============================================================================== --- branches/powerpc/reactos/tools/ppc-build/compdvr/fork_execvp.h (added) +++ branches/powerpc/reactos/tools/ppc-build/compdvr/fork_execvp.h Fri Jan 5 08:56:26 2007 @@ -1,0 +1,28 @@ +#ifndef FORK_EXECVP_H +#define FORK_EXECVP_H + +#include <string> +#include <vector> + +class ProcessHolder { +public: + virtual ~ProcessHolder() { } + virtual std::string ReadStdError() = 0; + virtual bool ProcessStarted() const = 0; + virtual bool EndOfStream() const = 0; + virtual int GetStatus() const = 0; +}; + +class Process { +public: + Process( ProcessHolder *h ) : holder(h) { } + ~Process() { delete holder; } + ProcessHolder *operator -> () const { return holder; } + operator ProcessHolder *() const { return (holder && holder->ProcessStarted()) ? holder : NULL; } +private: + ProcessHolder *holder; +}; + +ProcessHolder *fork_execvp( const std::vectorstd::string &args ); + +#endif//FORK_EXECVP_H
Propchange: branches/powerpc/reactos/tools/ppc-build/compdvr/fork_execvp.h ------------------------------------------------------------------------------ svn:executable = *
Added: branches/powerpc/reactos/tools/ppc-build/compdvr/fork_unix.cpp URL: http://svn.reactos.org/svn/reactos/branches/powerpc/reactos/tools/ppc-build/... ============================================================================== --- branches/powerpc/reactos/tools/ppc-build/compdvr/fork_unix.cpp (added) +++ branches/powerpc/reactos/tools/ppc-build/compdvr/fork_unix.cpp Fri Jan 5 08:56:26 2007 @@ -1,0 +1,66 @@ +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include "fork_execvp.h" + +class UnixProcessHolder : public ProcessHolder { +public: + UnixProcessHolder( const std::vectorstd::string &args ) + : read_fd(-1), child_pid(-1), at_end(false), status(-1) { + std::vector<char *> argvect(args.size()+1); + for( size_t i = 0; i < args.size(); i++ ) + argvect[i] = (char *)args[i].c_str(); + argvect[args.size()] = 0; + + int err_fd[2]; + + if( pipe( err_fd ) == -1 ) + return; + + fflush(stdout); + + child_pid = fork(); + + if( !child_pid ) { + dup2( err_fd[1], 2 ); + close( err_fd[0] ); + close( err_fd[1] ); + + execvp(args[0].c_str(), &argvect[0] ); + exit(1); + } else { + close( err_fd[1] ); + read_fd = err_fd[0]; + } + } + + ~UnixProcessHolder() { + close( read_fd ); + } + + std::string ReadStdError() { + char buf[1024]; + int rl = read( read_fd, buf, sizeof(buf) ); + if( rl < 1 ) { + at_end = true; + waitpid( child_pid, &status, 0 ); + return ""; + } + return std::string(buf, rl); + } + + bool ProcessStarted() const { return child_pid != -1; } + bool EndOfStream() const { return at_end; } + int GetStatus() const { return status; } + +private: + bool at_end; + int read_fd; + int child_pid; + int status; +}; + +ProcessHolder *fork_execvp( const std::vectorstd::string &args ) { + return new UnixProcessHolder( args ); +}
Propchange: branches/powerpc/reactos/tools/ppc-build/compdvr/fork_unix.cpp ------------------------------------------------------------------------------ svn:executable = *
Added: branches/powerpc/reactos/tools/ppc-build/compdvr/fork_win32.cpp URL: http://svn.reactos.org/svn/reactos/branches/powerpc/reactos/tools/ppc-build/... ============================================================================== --- branches/powerpc/reactos/tools/ppc-build/compdvr/fork_win32.cpp (added) +++ branches/powerpc/reactos/tools/ppc-build/compdvr/fork_win32.cpp Fri Jan 5 08:56:26 2007 @@ -1,0 +1,109 @@ +#include <windows.h> +#include "fork_execvp.h" + +class Win32ProcessHolder : public ProcessHolder { +public: + Win32ProcessHolder( const std::string &args ) + : ErrorRead(INVALID_HANDLE_VALUE), + ProcessHandle(INVALID_HANDLE_VALUE), + StreamEnded(false) { + HANDLE ErrorWrite = NULL, ErrorReadTemp = NULL; + PROCESS_INFORMATION pi = { }; + SECURITY_ATTRIBUTES sa = { }; + STARTUPINFO si = { }; + + sa.nLength = sizeof(sa); + sa.lpSecurityDescriptor = NULL; + sa.bInheritHandle = TRUE; + + if(!CreatePipe(&ErrorReadTemp, &ErrorWrite, &sa, 0)) return; + + if(!DuplicateHandle(GetCurrentProcess(), ErrorReadTemp, + GetCurrentProcess(), &ErrorRead, + 0, FALSE, + DUPLICATE_SAME_ACCESS)) return; + + CloseHandle(ErrorReadTemp); + + si.cb = sizeof(si); + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + si.hStdError = ErrorWrite; + + if(!CreateProcess(NULL, (char *)args.c_str(), NULL, NULL, TRUE, + 0, NULL, NULL, &si, &pi)) return; + + ProcessHandle = pi.hProcess; + + CloseHandle(ErrorWrite); + } + + ~Win32ProcessHolder() { + CloseHandle( ErrorRead ); + CloseHandle( ProcessHandle ); + } + + std::string ReadStdError() { + char Buf[1024]; + DWORD ReadBytes; + + if( StreamEnded ) return ""; + + StreamEnded = + !ReadFile(ErrorRead, Buf, sizeof(Buf), &ReadBytes, NULL) || + !ReadBytes; + + if( !StreamEnded ) return std::string(Buf, ReadBytes); + else return ""; + } + + bool EndOfStream() const { + return StreamEnded; + } + + bool ProcessStarted() const { + return ProcessHandle != INVALID_HANDLE_VALUE; + } + + int GetStatus() const { + DWORD Status = 1; + if( ProcessHandle != INVALID_HANDLE_VALUE ) { + WaitForSingleObject( ProcessHandle, INFINITE ); + GetExitCodeProcess( ProcessHandle, &Status ); + } + return Status; + } + +private: + bool StreamEnded; + HANDLE ErrorRead, ProcessHandle; +}; + +std::string quote_escape( const std::string &_str ) { + std::string str = _str; + size_t q; + + q = str.find('"'); + while( q != std::string::npos ) { + str.replace(q, 1, "\""); + q = str.find('"'); + } + + return std::string(""") + str + """; +} + +ProcessHolder *fork_execvp( const std::vectorstd::string &args ) { + std::string argstring; + ProcessHolder *holder; + + for( std::vectorstd::string::const_iterator i = args.begin(); + i != args.end(); + i++ ) { + if( i != args.begin() ) + argstring += " "; + argstring += quote_escape(*i); + } + + return new Win32ProcessHolder( argstring ); +}
Propchange: branches/powerpc/reactos/tools/ppc-build/compdvr/fork_win32.cpp ------------------------------------------------------------------------------ svn:executable = *