Added new embed utility for Windows

This commit is contained in:
Carsten Elton Sorensen 2012-11-13 09:11:49 +01:00
parent 53b1a2423a
commit 571cc6a85e
4 changed files with 293 additions and 1 deletions

View File

@ -496,6 +496,10 @@ ifeq ($(platform),windows)
else
shared += -Wl,--add-stdcall-alias
endif
embed = $(build-embed)/embed.exe
embed-loader = $(build-embed-loader)/embed-loader.exe
embed-loader-o = $(build-embed)/embed-loader.o
endif
ifeq ($(mode),debug)
@ -640,6 +644,15 @@ vm-asm-sources = $(src)/$(asm).S
target-asm = $(asm)
build-embed = $(build)/embed
build-embed-loader = $(build)/embed-loader
embed-loader-sources = $(src)/embedded-loader.cpp
embed-loader-objects = $(call cpp-objects,$(embed-loader-sources),$(src),$(build-embed-loader))
embed-sources = $(src)/embed.cpp
embed-objects = $(call cpp-objects,$(embed-sources),$(src),$(build-embed))
ifeq ($(process),compile)
vm-sources += \
$(src)/compiler.cpp \
@ -890,7 +903,7 @@ test-args = $(test-flags) $(input)
.PHONY: build
build: $(static-library) $(executable) $(dynamic-library) $(lzma-loader) \
$(lzma-encoder) $(executable-dynamic) $(classpath-dep) $(test-dep) \
$(test-extra-dep)
$(test-extra-dep) $(embed)
$(test-dep): $(classpath-dep)
@ -1005,6 +1018,38 @@ else
$(ld) $(^) $(shared) $(lflags) -o $(@)
endif
ifdef embed
$(embed): $(embed-objects) $(embed-loader-o)
@echo "building $(embed)"
$(build-cxx) $(^) -mwindows -mconsole -static -o $(@)
$(build-embed)/%.o: $(src)/%.cpp
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(build-cxx) -D_UNICODE -DUNICODE -c $(<) -o $(@)
$(embed-loader-o): $(embed-loader) $(converter)
@mkdir -p $(dir $(@))
$(converter) $(<) $(@) _binary_loader_start \
_binary_loader_end $(target-format) $(arch)
$(embed-loader): $(embed-loader-objects) $(static-library)
@mkdir -p $(dir $(@))
cd $(dir $(@)) && $(ar) x ../../../$(static-library)
$(dlltool) -z $(addsuffix .def,$(basename $(@))) $(dir $(@))/*.o
$(dlltool) -d $(addsuffix .def,$(basename $(@))) -e $(addsuffix .exp,$(basename $(@)))
$(cxx) $(addsuffix .exp,$(basename $(@))) $(dir $(@))/*.o -L../win32/lib -lmingwthrd -lm -lz -lws2_32 -liphlpapi \
-mwindows -mconsole -static -o $(@)
strip --strip-all $(@)
$(build-embed-loader)/%.o: $(src)/%.cpp
@echo "compiling $(@)"
@mkdir -p $(dir $(@))
$(cxx) -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/win32 \
-D_JNI_IMPLEMENTATION_ -c $(<) -o $(@)
endif
$(build)/%.o: $(lzma)/C/%.c
@echo "compiling $(@)"
@mkdir -p $(dir $(@))

125
src/embed.cpp Normal file
View File

@ -0,0 +1,125 @@
/* Copyright (c) 2008-2012, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#include <Windows.h>
#include <tchar.h>
#include <stdio.h>
#include <stdint.h>
#include <vector>
#include <string>
#include "embed.h"
extern "C" const uint8_t binary_loader_start[];
extern "C" const uint8_t binary_loader_end[];
__declspec(noreturn)
void printUsage(const wchar_t* executableName)
{
wprintf(L"Usage: %s destination.exe classes.jar package.Main\n", executableName);
exit(0);
}
void writeDestinationFile(const wchar_t* filename)
{
if(FILE* file = _wfopen(filename, L"wb"))
{
size_t count = binary_loader_end - binary_loader_start;
if(count == fwrite(binary_loader_start, sizeof(binary_loader_start[0]), count, file))
{
fclose(file);
return;
}
}
fprintf(stderr, "Unable to write to destination file\n");
exit(EXIT_FAILURE);
}
void readFile(std::vector<char>* jarFile, const wchar_t* fileName)
{
if(FILE* file = _wfopen(fileName, L"rb"))
{
fseek(file, 0, SEEK_END);
jarFile->resize(ftell(file));
fseek(file, 0, SEEK_SET);
fread(&jarFile->at(0), 1, jarFile->size(), file);
fclose(file);
}
}
bool mkStringSection(std::vector<wchar_t>* stringSection, const std::vector<std::wstring>& strings, int first, int last)
{
stringSection->clear();
for(int i = first; i <= last; ++i)
{
const std::wstring& s = strings.at(i);
stringSection->push_back(s.size());
stringSection->insert(stringSection->end(), s.begin(), s.end());
}
// pad to 16 entries
for(int i = last - first; i < 15; ++i)
stringSection->push_back(0);
return stringSection->size() > 16;
}
void writeStringResources(HANDLE hDest, const std::vector<std::wstring>& strings)
{
for(int i = 0; i < strings.size(); i += 16)
{
std::vector<wchar_t> stringSection;
if(mkStringSection(&stringSection, strings, i, std::min<int>(i + 15, strings.size() - 1)))
UpdateResourceW(hDest, RT_STRING, MAKEINTRESOURCE((i >> 4) + 1), LANG_NEUTRAL, &stringSection.at(0), sizeof(wchar_t) * stringSection.size());
}
}
int wmain(int argc, wchar_t* argv[])
{
if(argc != 4)
printUsage(argv[0]);
const wchar_t* destinationName = argv[1];
const wchar_t* classesName = argv[2];
const wchar_t* mainClassName = argv[3];
writeDestinationFile(destinationName);
if(HANDLE hDest = BeginUpdateResourceW(destinationName, TRUE))
{
std::vector<std::wstring> strings;
strings.resize(RESID_MAIN_CLASS + 1);
strings.at(RESID_MAIN_CLASS) = mainClassName;
writeStringResources(hDest, strings);
std::vector<char> jarFile;
readFile(&jarFile, classesName);
UpdateResourceW(hDest, RT_RCDATA, _T(RESID_BOOT_JAR), LANG_NEUTRAL, &jarFile.at(0), jarFile.size());
EndUpdateResource(hDest, FALSE);
}
return 0;
}
extern "C" int _CRT_glob;
extern "C" void __wgetmainargs(int*, wchar_t***, wchar_t***, int, int*);
int main()
{
wchar_t **enpv, **argv;
int argc, si = 0;
__wgetmainargs(&argc, &argv, &enpv, _CRT_glob, &si);
return wmain(argc, argv);
}

17
src/embed.h Normal file
View File

@ -0,0 +1,17 @@
/* Copyright (c) 2008-2012, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#ifndef EMBED_H
#define EMBED_H
#define RESID_MAIN_CLASS 100
#define RESID_BOOT_JAR "BOOT.JAR"
#endif

105
src/embedded-loader.cpp Normal file
View File

@ -0,0 +1,105 @@
/* Copyright (c) 2008-2012, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
#include <Windows.h>
#include <tchar.h>
#include <stdint.h>
#include "embed.h"
#include "jni.h"
#if (defined __MINGW32__) || (defined _MSC_VER)
# define EXPORT __declspec(dllexport)
#else
# define EXPORT __attribute__ ((visibility("default"))) \
__attribute__ ((used))
#endif
extern "C" {
EXPORT const uint8_t*
bootJar(unsigned* size)
{
if(HRSRC hResInfo = FindResource(NULL, _T(RESID_BOOT_JAR), RT_RCDATA))
{
if(HGLOBAL hRes = LoadResource(NULL, hResInfo))
{
*size = SizeofResource(NULL, hResInfo);
return (const uint8_t*)LockResource(hRes);
}
}
fprintf(stderr, "boot.jar resource not found\n");
*size = 0;
return NULL;
}
} // extern "C"
static bool getMainClass(char* pName, int maxLen)
{
if(0 == LoadString(NULL, RESID_MAIN_CLASS, pName, maxLen))
{
fprintf(stderr, "Main class not specified\n");
strcpy(pName, "Main");
}
}
int
main(int ac, const char** av)
{
JavaVMInitArgs vmArgs;
vmArgs.version = JNI_VERSION_1_2;
vmArgs.nOptions = 1;
vmArgs.ignoreUnrecognized = JNI_TRUE;
JavaVMOption options[vmArgs.nOptions];
vmArgs.options = options;
options[0].optionString = const_cast<char*>("-Xbootclasspath:[bootJar]");
JavaVM* vm;
void* env;
JNI_CreateJavaVM(&vm, &env, &vmArgs);
JNIEnv* e = static_cast<JNIEnv*>(env);
char mainClass[256];
getMainClass(mainClass, sizeof(mainClass));
jclass c = e->FindClass(mainClass);
if (not e->ExceptionCheck()) {
jmethodID m = e->GetStaticMethodID(c, "main", "([Ljava/lang/String;)V");
if (not e->ExceptionCheck()) {
jclass stringClass = e->FindClass("java/lang/String");
if (not e->ExceptionCheck()) {
jobjectArray a = e->NewObjectArray(ac-1, stringClass, 0);
if (not e->ExceptionCheck()) {
for (int i = 1; i < ac; ++i) {
e->SetObjectArrayElement(a, i-1, e->NewStringUTF(av[i]));
}
e->CallStaticVoidMethod(c, m, a);
} else fprintf(stderr, "Couldn't create array\n");
} else fprintf(stderr, "java.lang.String not found\n");
} else fprintf(stderr, "main method not found\n");
} else fprintf(stderr, "Main class not found\n");
int exitCode = 0;
if(e->ExceptionCheck()) {
exitCode = -1;
e->ExceptionDescribe();
e->ExceptionClear();
}
vm->DestroyJavaVM();
return exitCode;
}