mirror of https://github.com/flysand7/ciabatta.git
Make it compile on windows
This commit is contained in:
parent
5e177fae50
commit
1f811d7646
99
build.py
99
build.py
|
@ -7,10 +7,6 @@ import os
|
|||
import sys
|
||||
import pyjson5
|
||||
|
||||
dependencies = [
|
||||
'nasm',
|
||||
'llvm-ar'
|
||||
]
|
||||
|
||||
# Parse command line arguments
|
||||
arg_parser = argparse.ArgumentParser('build.py')
|
||||
|
@ -23,17 +19,25 @@ arg_parser.add_argument('--cflags', nargs='*', default=[], help='Pass additional
|
|||
args = arg_parser.parse_args()
|
||||
compiler = args.compiler
|
||||
|
||||
print('==> Performing basic checks')
|
||||
|
||||
# Perform cleaning if required
|
||||
def rm(path):
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
if args.clean:
|
||||
shutil.rmtree('bin')
|
||||
shutil.rmtree('lib')
|
||||
os.remove(os.path.join('src', 'ciabatta.c'))
|
||||
os.remove('a')
|
||||
if os.path.exists('bin'):
|
||||
shutil.rmtree('bin')
|
||||
if os.path.exists('lib'):
|
||||
shutil.rmtree('lib')
|
||||
rm(os.path.join('src', 'ciabatta.c'))
|
||||
rm('a')
|
||||
rm('a.exe')
|
||||
rm('a.ilk')
|
||||
rm('a.pdb')
|
||||
sys.exit(0)
|
||||
|
||||
# Check host OS
|
||||
print('==> Performing basic checks')
|
||||
target = args.target
|
||||
if target is None:
|
||||
host_os = platform.system().lower()
|
||||
|
@ -44,8 +48,31 @@ if target is None:
|
|||
target = host_os
|
||||
|
||||
# Add compiler to dependencies
|
||||
dependencies = [
|
||||
'nasm',
|
||||
'llvm-ar'
|
||||
]
|
||||
dependencies.append(args.compiler)
|
||||
|
||||
|
||||
# Figure out the flags
|
||||
includes = ['include']
|
||||
cc = args.compiler
|
||||
cc_defines = []
|
||||
cc_flags = ['-nostdlib']
|
||||
crt_file = 'crt.lib'
|
||||
lib_file = 'cia.lib'
|
||||
if args.mode == 'release':
|
||||
cc_flags.append('-O2')
|
||||
cc_defines.append('NDEBUG')
|
||||
else: # 'debug'
|
||||
cc_flags.append('-g')
|
||||
cc_flags.append('-O0')
|
||||
cc_defines.append('DEBUG')
|
||||
if target != 'windows':
|
||||
cc_flags.append('-fpic')
|
||||
cc_defines.append(f'_CIA_OS_{target.upper()}')
|
||||
|
||||
# Check dependencies
|
||||
print('==> Checking dependencies')
|
||||
for dependency in dependencies:
|
||||
|
@ -54,24 +81,6 @@ for dependency in dependencies:
|
|||
sys.exit(1)
|
||||
print(' -> Everything OK')
|
||||
|
||||
# Figure out the flags
|
||||
includes = ['include']
|
||||
cc = ''
|
||||
cc_defines = []
|
||||
cc_flags = ['-nostdlib']
|
||||
crt_file = 'crt.lib'
|
||||
lib_file = 'cia.lib'
|
||||
|
||||
cc = args.compiler
|
||||
if args.mode == 'release':
|
||||
cc_flags.append('-O2')
|
||||
cc_defines.append('NDEBUG')
|
||||
else: # 'debug'
|
||||
cc_flags.append('-g')
|
||||
cc_flags.append('-O0')
|
||||
cc_defines.append('DEBUG')
|
||||
cc_defines.append(f'_CIA_OS_{target.upper()}')
|
||||
|
||||
# Generate TinyRT headers for the target platform
|
||||
print(f"==> Generating TinyRT header for {target}")
|
||||
tinyrt_config_path = os.path.join('src', target, 'tinyrt.json')
|
||||
|
@ -133,8 +142,8 @@ try:
|
|||
if platform_config is None:
|
||||
print(f" -> [ERROR] library config doesn't contain configuration for platform {target}")
|
||||
for include in platform_config['includes']:
|
||||
include_path = os.path.join(platform_config['path'], include)
|
||||
ciabatta_header.write(f'#include "{include_path}"\n')
|
||||
include_path = platform_config['path']
|
||||
ciabatta_header.write(f'#include "{include_path}/{include}"\n')
|
||||
ciabatta_header.write(f'#include "{target}/tinyrt-iface.h"\n')
|
||||
ciabatta_header.write(f'#include <tinyrt.h>\n')
|
||||
for tinyrt_source in platform_config['tinyrt']:
|
||||
|
@ -193,7 +202,7 @@ def assemble(src, out):
|
|||
def compile(srcs, out, extra_flags = ''):
|
||||
flags = cc_flags_str + ' ' + extra_flags + ' '.join(args.cflags)
|
||||
inputs = ' '.join(map(quote, srcs))
|
||||
cmdline = f'{compiler} {flags} {inputs} -o {quote(out)}'
|
||||
cmdline = f'{cc} {flags} {inputs} -o {quote(out)}'
|
||||
print(' >', cmdline)
|
||||
code = os.system(cmdline)
|
||||
if code != 0:
|
||||
|
@ -207,20 +216,34 @@ def archive(srcs, out):
|
|||
if code != 0:
|
||||
sys.exit(code)
|
||||
|
||||
|
||||
# Ciabatta build spec
|
||||
if not os.path.exists('lib'):
|
||||
os.mkdir('lib')
|
||||
if not os.path.exists('bin'):
|
||||
os.mkdir('bin')
|
||||
|
||||
p = os.path.join
|
||||
def p(path):
|
||||
l = path.split('/')
|
||||
return os.path.join(*l)
|
||||
|
||||
assemble(p('src', 'linux', 'crt-entry.asm'), p('bin', 'crt-entry.o'))
|
||||
compile([p('src', 'linux', 'crt-ctors.c')], p('bin', 'crt-ctors.o'), '-fpic -c')
|
||||
compile([p('src', 'ciabatta.c')], p('bin', 'ciabatta.o'), '-fpic -c')
|
||||
archive([p('bin', 'crt-ctors.o'), p('bin', 'crt-entry.o')], p('lib', crt_file))
|
||||
archive([p('bin', 'ciabatta.o'), ], p('lib', lib_file))
|
||||
cia_lib = p(f'lib/{lib_file}')
|
||||
crt_lib = p(f'lib/{crt_file}')
|
||||
ciabatta_c = p('src/ciabatta.c')
|
||||
ciabatta_o = p('bin/ciabatta.o')
|
||||
|
||||
if target == 'linux':
|
||||
assemble(p('src/linux/crt-entry.asm'), p('bin/crt-entry.o'))
|
||||
compile([p('src/linux/crt-ctors.c')], p('bin/crt-ctors.o'), '-c')
|
||||
archive([p('bin/crt-ctors.o'), p('bin/crt-entry.o')], p('lib', crt_file))
|
||||
elif target == 'windows':
|
||||
assemble(p('src/windows/chkstk.asm'), p('bin/chkstk.o'))
|
||||
compile([p('src/windows/crt-entry.c')], p('bin/crt-entry.o'), '-c')
|
||||
archive([p('bin/crt-entry.o')], crt_lib)
|
||||
compile([ciabatta_c], ciabatta_o, '-c')
|
||||
archive([ciabatta_o], cia_lib)
|
||||
|
||||
if args.test:
|
||||
compile([args.test, p('lib', lib_file), p('lib', crt_file)], 'a', '-pie')
|
||||
if target == 'linux':
|
||||
compile([args.test, cia_lib, crt_lib], 'a', '-pie')
|
||||
elif target == 'windows':
|
||||
compile([args.test, cia_lib, crt_lib], 'a.exe', '-lkernel32')
|
||||
|
|
|
@ -1,9 +1,16 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// Since we're re-defining noreturn below, this would mess
|
||||
// with __declspec(noreturn) in windows headers, which
|
||||
// is hidden behind a define. Good thing, because now we
|
||||
// can override that define over here.
|
||||
#if defined(_CIA_OS_WINDOWS)
|
||||
#define DECLSPEC_NORETURN __declspec("noreturn")
|
||||
#endif
|
||||
|
||||
// Pre-C23 keyword macros and stddef
|
||||
#define static_assert _Static_assert
|
||||
#define noreturn _Noreturn
|
||||
#define NULL ((void *)0)
|
||||
|
||||
// Assert commonly-accepted platform-invariant sizes
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
int atexit(void (*func)(void));
|
||||
int at_quick_exit(void (*func)(void));
|
||||
noreturn void abort(void);
|
||||
noreturn void exit(int code);
|
||||
noreturn void _Exit(int code);
|
||||
noreturn void quick_exit(int code);
|
||||
[[noreturn]] void abort(void);
|
||||
[[noreturn]] void exit(int code);
|
||||
[[noreturn]] void _Exit(int code);
|
||||
[[noreturn]] void quick_exit(int code);
|
|
@ -41,7 +41,7 @@ static _RT_Status _rt_deinit();
|
|||
|
||||
// Program API
|
||||
#if _RT_API_PROGRAM == 1
|
||||
static noreturn void _rt_program_exit(int code);
|
||||
[[noreturn]] static void _rt_program_exit(int code);
|
||||
#endif
|
||||
|
||||
#if _RT_API_ENVIRONMENT == 1
|
||||
|
|
|
@ -25,12 +25,13 @@ int at_quick_exit(void (*func)(void)) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
noreturn void abort(void) {
|
||||
[[noreturn]] void abort(void) {
|
||||
// TODO: Ideally do a debug trap if the process is being debugged
|
||||
_Exit(-1);
|
||||
_rt_program_exit(1);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
noreturn void exit(int code) {
|
||||
[[noreturn]] void exit(int code) {
|
||||
for(u64 i = n_atexit_handlers-1; i-- != 0; ) {
|
||||
void (*handler)(void) = atexit_handlers[i];
|
||||
handler();
|
||||
|
@ -38,17 +39,20 @@ noreturn void exit(int code) {
|
|||
// TODO(bumbread): flush all the unflushed file streams
|
||||
// TODO(bumbread): close all file streams and delete temporary files
|
||||
_rt_program_exit(code);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
noreturn void _Exit(int code) {
|
||||
[[noreturn]] void _Exit(int code) {
|
||||
_rt_program_exit(code);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
noreturn void quick_exit(int code) {
|
||||
[[noreturn]] void quick_exit(int code) {
|
||||
for(u64 i = n_at_quick_exit_handlers-1; i-- != 0; ) {
|
||||
void (*handler)(void) = at_quick_exit_handlers[i];
|
||||
handler();
|
||||
}
|
||||
_rt_program_exit(code);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
|
|
|
@ -44,8 +44,13 @@ platforms: [
|
|||
{
|
||||
name: "windows",
|
||||
path: "windows",
|
||||
includes: [],
|
||||
tinyrt: [],
|
||||
includes: [
|
||||
"windows.c"
|
||||
],
|
||||
tinyrt: [
|
||||
"tinyrt.c",
|
||||
"cia-init.c"
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
|
||||
// See src/tinyrt.h file for the interface this file implements
|
||||
|
||||
static _RT_File _rt_file_stdin;
|
||||
static _RT_File _rt_file_stderr;
|
||||
|
||||
static _RT_Status _rt_file_std_handles_init() {
|
||||
_rt_file_stdin.fd = 0;
|
||||
_rt_file_stdin.flags = _RT_FILE_READ;
|
||||
|
@ -68,6 +65,6 @@ static _RT_Status _rt_file_close(_RT_File *file) {
|
|||
return _RT_STATUS_OK;
|
||||
}
|
||||
|
||||
static noreturn void _rt_program_exit(int code) {
|
||||
[[noreturn]] static void _rt_program_exit(int code) {
|
||||
syscall_exit(code);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
bits 64
|
||||
|
||||
segment .text
|
||||
global __chkstk
|
||||
__chkstk:
|
||||
sub rsp, 0x10
|
||||
mov [rsp], r10
|
||||
mov [rsp+0x8], r11
|
||||
xor r11, r11
|
||||
lea r10, [rsp+0x18]
|
||||
sub r10, rax
|
||||
cmovb r10, r11
|
||||
mov r11, gs:[0x10]
|
||||
cmp r10, r11
|
||||
jnb .end
|
||||
and r10w, 0xf000
|
||||
.loop:
|
||||
lea r11, [r11-0x1000]
|
||||
mov byte [r11], 0x0
|
||||
cmp r10, r11
|
||||
jnz .loop
|
||||
.end:
|
||||
mov r10, [rsp]
|
||||
mov r11, [rsp+0x8]
|
||||
add rsp, 0x10
|
||||
ret
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
static void _fileapi_init();
|
||||
|
||||
void _cia_init() {
|
||||
_fileapi_init();
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
|
||||
#include <cia-def.h>
|
||||
#include "windows.c"
|
||||
|
||||
extern int main(int argc, char **argv, char **envp);
|
||||
extern void _cia_init();
|
||||
|
||||
void mainCRTStartup() {
|
||||
_cia_init();
|
||||
__security_init_cookie();
|
||||
main(0, NULL, NULL);
|
||||
ExitProcess(0);
|
||||
}
|
||||
|
||||
void wmainCRTStartup() {
|
||||
ExitProcess(0);
|
||||
}
|
||||
|
||||
void _WinMainCRTStartup() {
|
||||
ExitProcess(0);
|
||||
}
|
||||
|
||||
void wWinMainCRTStartup() {
|
||||
ExitProcess(0);
|
||||
}
|
||||
|
||||
BOOL _DllMainCRTStartup(HINSTANCE instance, DWORD reason, void *_reserved) {
|
||||
switch(reason) {
|
||||
case DLL_PROCESS_ATTACH: {
|
||||
// Initialize once for each new process.
|
||||
// Return FALSE to fail DLL load.
|
||||
} break;
|
||||
case DLL_THREAD_ATTACH: {
|
||||
// Do thread-specific initialization.
|
||||
} break;
|
||||
case DLL_THREAD_DETACH: {
|
||||
// Do thread-specific cleanup.
|
||||
} break;
|
||||
case DLL_PROCESS_DETACH: {
|
||||
// Perform any necessary cleanup.
|
||||
} break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
u64 __security_cookie;
|
||||
|
||||
void __security_init_cookie() {
|
||||
// They say it's a random number so I generated
|
||||
// one using numbergenerator.org
|
||||
__security_cookie = 0xb26e04cc62ba48aULL;
|
||||
}
|
||||
|
||||
void __security_check_cookie(u64 retrieved) {
|
||||
if(__security_cookie != retrieved) {
|
||||
char buf[] = "Buffer overrun detected!\n";
|
||||
HANDLE stdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
WriteFile(stdout, buf, sizeof buf, NULL, NULL);
|
||||
// TODO: abort-like behaviour here
|
||||
ExitProcess(1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
// See src/tinyrt.h file for the interface this file implements
|
||||
|
||||
static _RT_Status _rt_file_std_handles_init() {
|
||||
_rt_file_stdin.handle = GetStdHandle(STD_INPUT_HANDLE);
|
||||
_rt_file_stdin.flags = _RT_FILE_READ;
|
||||
_rt_file_stdout.handle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
_rt_file_stdout.flags = _RT_FILE_WRITE;
|
||||
_rt_file_stderr.handle = GetStdHandle(STD_ERROR_HANDLE);
|
||||
_rt_file_stdout.flags = _RT_FILE_WRITE;
|
||||
return _RT_STATUS_OK;
|
||||
}
|
||||
|
||||
static _RT_Status _rt_file_open(_RT_File *file, char const *name, int _rt_flags) {
|
||||
u32 access = 0;
|
||||
if(_rt_flags & _RT_FILE_READ) access |= GENERIC_READ;
|
||||
if(_rt_flags & _RT_FILE_WRITE) access |= GENERIC_WRITE;
|
||||
u32 share = 0;
|
||||
if((_rt_flags & _RT_FILE_READ) == 0) share |= FILE_SHARE_READ;
|
||||
u32 creation = 0;
|
||||
if(_rt_flags & _RT_FILE_TRUNCATE) {
|
||||
creation = TRUNCATE_EXISTING;
|
||||
}
|
||||
else if(_rt_flags & _RT_FILE_CREATE) {
|
||||
if(_rt_flags & _RT_FILE_EXCLUSIVE) creation = CREATE_ALWAYS;
|
||||
else creation = CREATE_NEW;
|
||||
}
|
||||
else {
|
||||
if(_rt_flags & _RT_FILE_EXCLUSIVE) creation = OPEN_ALWAYS;
|
||||
else creation = OPEN_EXISTING;
|
||||
}
|
||||
HANDLE handle = CreateFileA(name, access, share, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if(file == INVALID_HANDLE_VALUE) {
|
||||
// ERROR_FILE_NOT_FOUND
|
||||
// ERROR_PATH_NOT_FOUND
|
||||
// ERROR_ACCESS_DENIED
|
||||
// ERROR_NOT_ENOUGH_MEMORY
|
||||
return _RT_STATUS_FILE_IO_ERROR;
|
||||
|
||||
}
|
||||
file->handle = handle;
|
||||
file->flags = _rt_flags;
|
||||
return _RT_STATUS_OK;
|
||||
}
|
||||
|
||||
static _RT_Status _rt_file_read(u64 size, void *buffer, _RT_File *from, u64 *out_bytes_read) {
|
||||
*out_bytes_read = 0;
|
||||
BOOL ok = ReadFile(from->handle, buffer, size, (unsigned long *)out_bytes_read, NULL);
|
||||
if(!ok) {
|
||||
return _RT_STATUS_FILE_IO_ERROR;
|
||||
}
|
||||
return _RT_STATUS_OK;
|
||||
}
|
||||
|
||||
static _RT_Status _rt_file_write(_RT_File *to, u64 size, void *buffer, u64 *out_bytes_written) {
|
||||
*out_bytes_written = 0;
|
||||
BOOL ok = WriteFile(to->handle, buffer, size, (unsigned long *)out_bytes_written, NULL);
|
||||
if(!ok) {
|
||||
return _RT_STATUS_FILE_IO_ERROR;
|
||||
}
|
||||
return _RT_STATUS_OK;
|
||||
}
|
||||
|
||||
static _RT_Status _rt_file_close(_RT_File *file) {
|
||||
BOOL ok = CloseHandle(file->handle);
|
||||
if(!ok) {
|
||||
return _RT_STATUS_FILE_BAD_FILE;
|
||||
}
|
||||
return _RT_STATUS_OK;
|
||||
}
|
||||
|
||||
[[noreturn]] static void _rt_program_exit(int code) {
|
||||
ExitProcess(code);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
|
||||
// This file contains TinyRT API subsets that are exported
|
||||
// for this operating system, one name per line. This file
|
||||
// is used in a build script to generate tinyrt_macro file
|
||||
// and to resolve higher-level API dependencies
|
||||
|
||||
rt_api_file: true,
|
||||
rt_api_program: true,
|
||||
rt_api_shell: false,
|
||||
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
#define NOGDI
|
||||
#define NOUSER
|
||||
#define NOMINMAX
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
|
@ -1,9 +1,4 @@
|
|||
|
||||
#include <cia-def.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
char string[] = "Hello, world!\n";
|
||||
fwrite(string, 1, sizeof string-1, stdout);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
#include <cia-def.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
char string[] = "Hello, world!\n";
|
||||
fwrite(string, 1, sizeof string-1, stdout);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue