diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 00000000..fe43a7d6 Binary files /dev/null and b/.DS_Store differ diff --git a/kmake/src/Exporters/MacOSExporter.ts b/kmake/src/Exporters/MacOSExporter.ts new file mode 100644 index 00000000..17ac3bb7 --- /dev/null +++ b/kmake/src/Exporters/MacOSExporter.ts @@ -0,0 +1,83 @@ +import { Exporter } from 'kmake/Exporters/Exporter'; +import { Options } from 'kmake/Options'; +import { Platform } from 'kmake/Platform'; +import { Project } from 'kmake/Project'; +import { Compiler } from 'kmake/Compiler'; +import * as fs from 'kmake/fsextra'; +import * as path from 'path'; +import { NinjaExporter } from 'kmake/Exporters/NinjaExporter'; +import { MakeExporter } from 'kmake/Exporters/MakeExporter'; +import { CLionExporter } from 'kmake/Exporters/CLionExporter'; +import { CompilerCommandsExporter } from 'kmake/Exporters/CompileCommandsExporter'; + +export class MacOSExporter extends Exporter { + ninja: NinjaExporter; + make: MakeExporter; + clion: CLionExporter; + compileCommands: CompilerCommandsExporter; + + constructor(options: any) { + super(options); + + let linkerFlags = '-pthread'; + if (options.lib) { + linkerFlags += ' -static'; + } + + let outputExtension = ''; + if (options.lib) { + outputExtension = '.a'; + } + else if (options.dynlib) { + outputExtension = '.dylib'; + } + + this.ninja = new NinjaExporter(options, this.getCCompiler(), this.getCPPCompiler(), '', '', linkerFlags, outputExtension); + this.make = new MakeExporter(options, this.getCCompiler(), this.getCPPCompiler(), '', '', linkerFlags, outputExtension); + this.clion = new CLionExporter(options); + this.compileCommands = new CompilerCommandsExporter(options); + } + + async exportSolution(project: Project, from: string, to: string, platform: string, vrApi: any, options: any) { + // Debug: log .m files before export + console.log('MacOSExporter: Total files:', project.getFiles().length); + for (let fileobject of project.getFiles()) { + if (fileobject.file.endsWith('.m') || fileobject.file.endsWith('.mm')) { + console.log('MacOSExporter: Found .m file:', fileobject.file); + } + } + + this.ninja.exportSolution(project, from, to, platform, vrApi, options); + this.make.exportSolution(project, from, to, platform, vrApi, options); + this.clion.exportSolution(project, from, to, platform, vrApi, options); + this.compileCommands.exportSolution(project, from, to, platform, vrApi, options); + } + + getCCompiler(): string { + switch (Options.compiler) { + case Compiler.Default: + case Compiler.Clang: + return 'clang'; + case Compiler.GCC: + return 'gcc'; + case Compiler.Custom: + return Options.ccPath; + default: + throw 'Unsupported compiler ' + Options.compiler; + } + } + + getCPPCompiler(): string { + switch (Options.compiler) { + case Compiler.Default: + case Compiler.Clang: + return 'clang++'; + case Compiler.GCC: + return 'g++'; + case Compiler.Custom: + return Options.cxxPath; + default: + throw 'Unsupported compiler ' + Options.compiler; + } + } +} diff --git a/kmake/src/Exporters/MakeExporter.ts b/kmake/src/Exporters/MakeExporter.ts index b222cc96..1b14d053 100644 --- a/kmake/src/Exporters/MakeExporter.ts +++ b/kmake/src/Exporters/MakeExporter.ts @@ -33,6 +33,27 @@ export class MakeExporter extends Exporter { } async exportSolution(project: Project, from: string, to: string, platform: string, vrApi: any, options: any) { + let mFiles = [ + path.join(from, 'Kinc/Backends/System/Apple/Sources/kinc/backend/appleunit.m'), + path.join(from, 'Kinc/Backends/System/macOS/Sources/kinc/backend/macosunit.m'), + path.join(from, 'Kinc/Backends/System/macOS/Sources/kinc/backend/system.m.h'), + path.join(from, 'Kinc/Backends/System/macOS/Sources/kinc/backend/BasicOpenGLView.m.h'), + path.join(from, 'Kinc/Backends/System/macOS/Sources/kinc/backend/display.m.h'), + path.join(from, 'Kinc/Backends/System/macOS/Sources/kinc/backend/mouse.m.h') + ]; + for (let mFile of mFiles) { + let found = false; + for (let fileobject of project.getFiles()) { + if (fileobject.file === mFile) { + found = true; + break; + } + } + if (!found) { + project.files.push({file: mFile, options: null, projectDir: from, projectName: project.name}); + } + } + let objects: any = {}; let ofiles: any = {}; let outputPath = path.resolve(to, options.buildPath); @@ -40,7 +61,7 @@ export class MakeExporter extends Exporter { for (let fileobject of project.getFiles()) { let file = fileobject.file; - if (file.endsWith('.cpp') || file.endsWith('.c') || file.endsWith('.cc') || file.endsWith('.s') || file.endsWith('.S')) { + if (file.endsWith('.cpp') || file.endsWith('.c') || file.endsWith('.cc') || file.endsWith('.s') || file.endsWith('.S') || file.endsWith('.m') || file.endsWith('.mm') || file.endsWith('.m.h')) { if (fileobject.options && fileobject.options.nocompile) { continue; } @@ -192,7 +213,7 @@ export class MakeExporter extends Exporter { for (let fileobject of project.getFiles()) { let file = fileobject.file; - if (file.endsWith('.c') || file.endsWith('.cpp') || file.endsWith('.cc') || file.endsWith('.s') || file.endsWith('.S')) { + if (file.endsWith('.c') || file.endsWith('.cpp') || file.endsWith('.cc') || file.endsWith('.s') || file.endsWith('.S') || file.endsWith('.m') || file.endsWith('.mm') || file.endsWith('.m.h')) { if (fileobject.options && fileobject.options.nocompile) { continue; } @@ -215,6 +236,14 @@ export class MakeExporter extends Exporter { compiler = this.cCompiler; flags = ''; } + else if (file.endsWith('.m') || file.endsWith('.m.h')) { + compiler = this.cCompiler; + flags = '$(CPPFLAGS)'; + } + else if (file.endsWith('.mm')) { + compiler = this.cppCompiler; + flags = '$(CPPFLAGS)'; + } this.p('\t' + compiler + ' ' + optimization + ' $(INC) $(DEF) -MD ' + flags + ' -c ' + realfile + ' -o ' + name + '.o'); } diff --git a/kmake/src/Project.ts b/kmake/src/Project.ts index f20cc8e1..127a051b 100644 --- a/kmake/src/Project.ts +++ b/kmake/src/Project.ts @@ -516,7 +516,8 @@ export class Project { } matches(text: string, pattern: string) { - const regexstring = pattern.replace(/\./g, '\\.').replace(/\*\*/g, '.?').replace(/\*/g, '[^/]*').replace(/\?/g, '*'); + //const regexstring = pattern.replace(/\./g, '\\.').replace(/\*\*/g, '.?').replace(/\*/g, '[^/]*').replace(/\?/g, '*'); + const regexstring = pattern.replace(/\./g, '\\.').replace(/\*\*/g, '.*').replace(/\*/g, '[^/]*').replace(/\?/g, '.'); const regex = new RegExp('^' + regexstring + '$', 'g'); return regex.test(text); } diff --git a/kmake/src/main.ts b/kmake/src/main.ts index 9f0d46b6..be5223d6 100644 --- a/kmake/src/main.ts +++ b/kmake/src/main.ts @@ -11,6 +11,8 @@ import { VisualStudioVersion } from 'kmake/VisualStudioVersion'; import { Exporter } from 'kmake/Exporters/Exporter'; import { AndroidExporter } from 'kmake/Exporters/AndroidExporter'; import { LinuxExporter } from 'kmake/Exporters/LinuxExporter'; +import { MacOSExporter } from 'kmake/Exporters/MacOSExporter'; +import { MakeExporter } from 'kmake/Exporters/MakeExporter'; import { EmscriptenExporter } from 'kmake/Exporters/EmscriptenExporter'; import { WasmExporter } from 'kmake/Exporters/WasmExporter'; import { VisualStudioExporter } from 'kmake/Exporters/VisualStudioExporter'; @@ -628,7 +630,22 @@ async function exportKoremakeProject(from: string, to: string, platform: string, else if (options.meson) { exporter = new MesonExporter(options); } - else if (platform === Platform.iOS || platform === Platform.OSX || platform === Platform.tvOS) exporter = new XCodeExporter(options); + else if (platform === Platform.OSX) { + // Use MakeExporter directly for macOS to ensure .m files are compiled + let linkerFlags = '-pthread'; + if (options.lib) { + linkerFlags += ' -static'; + } + let outputExtension = ''; + if (options.lib) { + outputExtension = '.a'; + } + else if (options.dynlib) { + outputExtension = '.dylib'; + } + exporter = new MakeExporter(options, 'clang', 'clang++', '', '', linkerFlags, outputExtension); + } + else if (platform === Platform.iOS || platform === Platform.tvOS) exporter = new XCodeExporter(options); else if (platform === Platform.Android) exporter = new AndroidExporter(options); else if (platform === Platform.Emscripten) exporter = new EmscriptenExporter(project, options); else if (platform === Platform.Wasm) exporter = new WasmExporter(options); @@ -1067,7 +1084,10 @@ export async function run(options: any, loglog: any): Promise { else if (isPlatform(options, Platform.FreeBSD)) { make = child_process.spawn('make', [], { cwd: path.join(options.to, options.buildPath) }); } - else if (isPlatform(options, Platform.OSX) || isPlatform(options, Platform.iOS) || isPlatform(options, Platform.tvOS)) { + else if (isPlatform(options, Platform.OSX)) { + make = child_process.spawn('make', [], { cwd: path.join(options.to, options.buildPath) }); + } + else if (isPlatform(options, Platform.iOS) || isPlatform(options, Platform.tvOS)) { let xcodeOptions = ['-configuration', options.debug ? 'Debug' : 'Release', '-project', solutionName + '.xcodeproj', '-quiet']; if (isPlatform(options, Platform.iOS)) {