161 lines
4.9 KiB
V
161 lines
4.9 KiB
V
module builder
|
|
|
|
import os
|
|
import config
|
|
import deps
|
|
|
|
pub fn build(mut build_config config.BuildConfig) ! {
|
|
println('Building ${build_config.project_name}...')
|
|
|
|
// Create directories
|
|
os.mkdir_all(build_config.build_dir) or { return error('Failed to create build directory') }
|
|
os.mkdir_all(build_config.bin_dir) or { return error('Failed to create bin directory') }
|
|
|
|
// Find all source files
|
|
source_files := find_source_files(build_config.src_dir) or {
|
|
return error('Failed to find source files in ${build_config.src_dir}')
|
|
}
|
|
|
|
if source_files.len == 0 {
|
|
return error('No source files found in ${build_config.src_dir}')
|
|
}
|
|
|
|
mut object_files := []string{}
|
|
|
|
// Compile each source file
|
|
for src_file in source_files {
|
|
obj_file := src_file.replace(build_config.src_dir, build_config.build_dir).replace('.cpp', '.o')
|
|
|
|
// Create object directory if needed
|
|
obj_dir := os.dir(obj_file)
|
|
os.mkdir_all(obj_dir) or { return error('Failed to create object directory: ${obj_dir}') }
|
|
|
|
// Check if we need to recompile
|
|
if needs_recompile(src_file, obj_file) {
|
|
println('Compiling ${src_file}...')
|
|
object_files << compile_file(src_file, obj_file, build_config) or {
|
|
return error('Failed to compile ${src_file}')
|
|
}
|
|
} else {
|
|
if build_config.verbose {
|
|
println('Using cached ${obj_file}')
|
|
}
|
|
object_files << obj_file
|
|
}
|
|
}
|
|
|
|
// Link object files
|
|
executable := os.join_path(build_config.bin_dir, build_config.project_name)
|
|
println('Linking ${executable}...')
|
|
link_objects(object_files, executable, build_config) or { return error('Failed to link executable') }
|
|
|
|
println('Build completed successfully!')
|
|
}
|
|
|
|
pub fn clean(build_config config.BuildConfig) {
|
|
println('Cleaning build files...')
|
|
|
|
// Remove build directory
|
|
if os.is_dir(build_config.build_dir) {
|
|
os.rmdir_all(build_config.build_dir) or {
|
|
println('Warning: Failed to remove ${build_config.build_dir}: ${err}')
|
|
}
|
|
println('Removed ${build_config.build_dir}')
|
|
}
|
|
|
|
// Remove executable
|
|
executable := os.join_path(build_config.bin_dir, build_config.project_name)
|
|
if os.is_file(executable) {
|
|
os.rm(executable) or {
|
|
println('Warning: Failed to remove ${executable}: ${err}')
|
|
}
|
|
println('Removed ${executable}')
|
|
}
|
|
|
|
println('Clean completed!')
|
|
}
|
|
|
|
fn find_source_files(dir string) ![]string {
|
|
mut files := []string{}
|
|
|
|
if !os.is_dir(dir) {
|
|
return error('Source directory does not exist: ${dir}')
|
|
}
|
|
|
|
items := os.ls(dir) or { return error('Failed to list directory: ${dir}') }
|
|
|
|
for item in items {
|
|
full_path := os.join_path(dir, item)
|
|
if os.is_file(full_path) {
|
|
if item.ends_with('.cpp') || item.ends_with('.cc') || item.ends_with('.cxx') {
|
|
files << full_path
|
|
}
|
|
} else if os.is_dir(full_path) {
|
|
// Recursively search subdirectories
|
|
sub_files := find_source_files(full_path)!
|
|
files << sub_files
|
|
}
|
|
}
|
|
|
|
return files
|
|
}
|
|
|
|
fn needs_recompile(source_file string, object_file string) bool {
|
|
src_mtime := os.file_last_mod_unix(source_file)
|
|
obj_mtime := if os.is_file(object_file) {
|
|
os.file_last_mod_unix(object_file)
|
|
} else {
|
|
0
|
|
}
|
|
|
|
// Source is newer than object
|
|
if src_mtime > obj_mtime {
|
|
return true
|
|
}
|
|
|
|
// Check dependencies
|
|
dependencies := deps.extract_dependencies(source_file) or { return true }
|
|
for dep in dependencies {
|
|
if !os.is_file(dep) {
|
|
return true
|
|
}
|
|
dep_mtime := os.file_last_mod_unix(dep)
|
|
if dep_mtime > obj_mtime {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
fn compile_file(source_file string, object_file string, build_config config.BuildConfig) !string {
|
|
cmd := config.build_compiler_command(source_file, object_file, build_config)
|
|
|
|
if build_config.verbose {
|
|
println('Compile command: ${cmd}')
|
|
}
|
|
|
|
res := os.execute(cmd)
|
|
if res.exit_code != 0 {
|
|
return error('Compilation failed with exit code ${res.exit_code}:\n${res.output}')
|
|
}
|
|
|
|
// Generate dependency file
|
|
dep_file := object_file.replace('.o', '.d')
|
|
deps.generate_dependency_file(source_file, object_file, dep_file)
|
|
|
|
return object_file
|
|
}
|
|
|
|
fn link_objects(object_files []string, executable string, build_config config.BuildConfig) ! {
|
|
cmd := config.build_linker_command(object_files, executable, build_config)
|
|
|
|
if build_config.verbose {
|
|
println('Link command: ${cmd}')
|
|
}
|
|
|
|
res := os.execute(cmd)
|
|
if res.exit_code != 0 {
|
|
return error('Linking failed with exit code ${res.exit_code}:\n${res.output}')
|
|
}
|
|
} |