From 3883a3674d20a6621140b9e45704c62d7acb4235 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Wed, 23 Oct 2019 07:12:36 -0700 Subject: [PATCH] Added Android support, and generalized target triple support Added PICLevel, RelocKind DarwinCommon/LinuxCommon/AndroidCommon merged into PosixCommon Mangling changed to avoid '@' --- BeefBoot/BeefBoot.cpp | 2 +- BeefBoot/BootApp.cpp | 6 +- BeefBuild/BeefProj.toml | 17 +- BeefRT/CMakeLists.txt | 82 +- BeefRT/rt/Internal.cpp | 4 +- .../platform/android/AndroidCommon.cpp | 8 + BeefySysLib/platform/android/AndroidCommon.h | 159 + BeefySysLib/platform/android/BFPlatform.cpp | 13 + BeefySysLib/platform/android/BFPlatform.h | 24 + BeefySysLib/platform/android/PlatformApp.h | 9 + BeefySysLib/platform/darwin/DarwinCommon.cpp | 3295 +---------------- BeefySysLib/platform/ios/BFPlatform.h | 1 + BeefySysLib/platform/linux/LinuxCommon.cpp | 2212 +---------- BeefySysLib/platform/osx/BFPlatform.h | 2 + BeefySysLib/platform/posix/PosixCommon.cpp | 2341 ++++++++++++ BeefySysLib/util/BeefPerf.cpp | 8 +- BeefySysLib/util/Hash.cpp | 8 + BeefySysLib/util/Hash.h | 4 + IDE/src/BuildContext.bf | 89 +- IDE/src/BuildOptions.bf | 19 + IDE/src/Compiler/BfCompiler.bf | 6 +- IDE/src/Compiler/BfProject.bf | 7 +- IDE/src/IDEApp.bf | 111 +- IDE/src/Project.bf | 77 +- IDE/src/Workspace.bf | 25 +- IDE/src/ui/ProjectProperties.bf | 4 +- IDE/src/ui/WorkspaceProperties.bf | 11 +- IDE/src/util/TargetTriple.bf | 55 + IDEHelper/Compiler/BfCompiler.cpp | 77 +- IDEHelper/Compiler/BfCompiler.h | 6 +- IDEHelper/Compiler/BfContext.cpp | 31 +- IDEHelper/Compiler/BfIRBuilder.cpp | 4 +- IDEHelper/Compiler/BfIRCodeGen.cpp | 42 +- IDEHelper/Compiler/BfMangler.cpp | 60 +- IDEHelper/Compiler/BfModule.cpp | 10 +- IDEHelper/Compiler/BfSystem.cpp | 6 +- IDEHelper/Compiler/BfSystem.h | 42 +- IDEHelper/IDEHelper.vcxproj | 4 +- bin/build_android.bat | 210 ++ 39 files changed, 3456 insertions(+), 5635 deletions(-) create mode 100644 BeefySysLib/platform/android/AndroidCommon.cpp create mode 100644 BeefySysLib/platform/android/AndroidCommon.h create mode 100644 BeefySysLib/platform/android/BFPlatform.cpp create mode 100644 BeefySysLib/platform/android/BFPlatform.h create mode 100644 BeefySysLib/platform/android/PlatformApp.h create mode 100644 BeefySysLib/platform/posix/PosixCommon.cpp create mode 100644 IDE/src/util/TargetTriple.bf create mode 100644 bin/build_android.bat diff --git a/BeefBoot/BeefBoot.cpp b/BeefBoot/BeefBoot.cpp index 561dbfd8d..b65873da5 100644 --- a/BeefBoot/BeefBoot.cpp +++ b/BeefBoot/BeefBoot.cpp @@ -33,7 +33,7 @@ BF_IMPORT void BF_CALLTYPE IDEHelper_ProgramStart(); BF_IMPORT void BF_CALLTYPE IDEHelper_ProgramDone(); int main(int argc, char* argv[]) -{ +{ #ifdef TEST_CRASH CrashCatcher catcher; catcher.SetCrashReportKind(BfpCrashReportKind_GUI); diff --git a/BeefBoot/BootApp.cpp b/BeefBoot/BootApp.cpp index 90cb52f38..0b8877a05 100644 --- a/BeefBoot/BootApp.cpp +++ b/BeefBoot/BootApp.cpp @@ -57,7 +57,7 @@ BF_IMPORT void BF_CALLTYPE BfSystem_AddTypeOptions(void* bfSystem, const char* f BF_IMPORT void BF_CALLTYPE BfProject_SetDisabled(void* bfProject, bool disabled); BF_IMPORT void BF_CALLTYPE BfProject_SetOptions(void* bfProject, int targetType, const char* startupObject, const char* preprocessorMacros, - int optLevel, int ltoType, int32 flags); + int optLevel, int ltoType, int relocType, int picLevel, int32 flags); BF_IMPORT void BF_CALLTYPE BfProject_ClearDependencies(void* bfProject); BF_IMPORT void BF_CALLTYPE BfProject_AddDependency(void* bfProject, void* depProject); @@ -795,7 +795,7 @@ bool BootApp::Compile() mCELibProject = BfSystem_CreateProject(mSystem, "BeefLib"); BfProjectFlags flags = BfProjectFlags_None; - BfProject_SetOptions(mCELibProject, BfTargetType_BeefLib, "", mDefines.c_str(), mOptLevel, 0, flags); + BfProject_SetOptions(mCELibProject, BfTargetType_BeefLib, "", mDefines.c_str(), mOptLevel, 0, 0, 0, flags); } if (!mDefines.IsEmpty()) @@ -815,7 +815,7 @@ bool BootApp::Compile() else if (mAsmKind == BfAsmKind_Intel) flags = (BfProjectFlags)(flags | BfProjectFlags_AsmOutput); } - BfProject_SetOptions(mProject, mTargetType, mStartupObject.c_str(), mDefines.c_str(), mOptLevel, ltoType, flags); + BfProject_SetOptions(mProject, mTargetType, mStartupObject.c_str(), mDefines.c_str(), mOptLevel, ltoType, 0, 0, flags); if (mCELibProject != NULL) BfProject_AddDependency(mProject, mCELibProject); diff --git a/BeefBuild/BeefProj.toml b/BeefBuild/BeefProj.toml index 5f60befd6..8d4d279b3 100644 --- a/BeefBuild/BeefProj.toml +++ b/BeefBuild/BeefProj.toml @@ -20,7 +20,7 @@ TargetName = "$(ProjectName)_d" OtherLinkFlags = "$(LinkFlags) Comdlg32.lib kernel32.lib user32.lib advapi32.lib shell32.lib IDEHelper64_d.lib Rpcrt4.lib Ole32.lib" CLibType = "Dynamic" BeefLibType = "DynamicDebug" -DebugCommandArguments = "--version" +DebugCommandArguments = "-platform=x86_64-none-linux-android21 -workspace=C:/proj/Android/BeefTest/app/src/main/cpp/../beef/\"" DebugWorkingDirectory = "c:\\beef\\ide\\mintest" EnvironmentVars = ["_NO_DEBUG_HEAP=1"] PreprocessorMacros = ["DEBUG", "CLI"] @@ -34,23 +34,22 @@ DebugCommandArguments = "-proddir=..\\ -config=Debug -platform=Win64" DebugWorkingDirectory = "$(WorkspaceDir)/../IDE/dist" PreprocessorMacros = ["DEBUG", "CLI"] -[Configs.Release.macOS] +[Configs.Debug.Linux64] TargetDirectory = "$(WorkspaceDir)/../IDE/dist" -OtherLinkFlags = "./libBeefRT.dylib ./libIDEHelper.dylib ./libBeefySysLib.dylib ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMCore.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMMC.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMMCParser.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMCodeGen.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86Disassembler.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMMCDisassembler.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMSupport.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86Info.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86Utils.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86AsmPrinter.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86Desc.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMObject.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMBitReader.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMAsmParser.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMTarget.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86CodeGen.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMScalarOpts.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMInstCombine.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMSelectionDAG.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMProfileData.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMTransformUtils.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMAnalysis.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86AsmParser.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMAsmPrinter.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMBitWriter.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMVectorize.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMipo.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMInstrumentation.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMDebugInfoDWARF.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMDebugInfoPDB.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMDebugInfoCodeView.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMGlobalISel.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMBinaryFormat.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMDemangle.a -Wl,-rpath -Wl,." +TargetName = "$(ProjectName)_d" +OtherLinkFlags = "./libBeefRT_d.so ./libIDEHelper_d.so ./libBeefySysLib_d.so ../../extern/llvm_linux_8_0_0/lib/libLLVMCore.a ../../extern/llvm_linux_8_0_0/lib/libLLVMMC.a ../../extern/llvm_linux_8_0_0/lib/libLLVMMCParser.a ../../extern/llvm_linux_8_0_0/lib/libLLVMCodeGen.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86Disassembler.a ../../extern/llvm_linux_8_0_0/lib/libLLVMMCDisassembler.a ../../extern/llvm_linux_8_0_0/lib/libLLVMSupport.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86Info.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86Utils.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86AsmPrinter.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86Desc.a ../../extern/llvm_linux_8_0_0/lib/libLLVMObject.a ../../extern/llvm_linux_8_0_0/lib/libLLVMBitReader.a ../../extern/llvm_linux_8_0_0/lib/libLLVMAsmParser.a ../../extern/llvm_linux_8_0_0/lib/libLLVMTarget.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86CodeGen.a ../../extern/llvm_linux_8_0_0/lib/libLLVMScalarOpts.a ../../extern/llvm_linux_8_0_0/lib/libLLVMInstCombine.a ../../extern/llvm_linux_8_0_0/lib/libLLVMSelectionDAG.a ../../extern/llvm_linux_8_0_0/lib/libLLVMProfileData.a ../../extern/llvm_linux_8_0_0/lib/libLLVMTransformUtils.a ../../extern/llvm_linux_8_0_0/lib/libLLVMAnalysis.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86AsmParser.a ../../extern/llvm_linux_8_0_0/lib/libLLVMAsmPrinter.a ../../extern/llvm_linux_8_0_0/lib/libLLVMBitWriter.a ../../extern/llvm_linux_8_0_0/lib/libLLVMVectorize.a ../../extern/llvm_linux_8_0_0/lib/libLLVMipo.a ../../extern/llvm_linux_8_0_0/lib/libLLVMInstrumentation.a ../../extern/llvm_linux_8_0_0/lib/libLLVMDebugInfoDWARF.a ../../extern/llvm_linux_8_0_0/lib/libLLVMDebugInfoPDB.a ../../extern/llvm_linux_8_0_0/lib/libLLVMDebugInfoCodeView.a ../../extern/llvm_linux_8_0_0/lib/libLLVMGlobalISel.a ../../extern/llvm_linux_8_0_0/lib/libLLVMBinaryFormat.a ../../extern/llvm_linux_8_0_0/lib/libLLVMDemangle.a -ltinfo -Wl,-rpath -Wl,$ORIGIN" CLibType = "Dynamic" DebugCommandArguments = "-proddir=..\\ -config=Debug -platform=Win64" DebugWorkingDirectory = "$(WorkspaceDir)/../IDE/dist" -PreprocessorMacros = ["CLI"] - +PreprocessorMacros = ["DEBUG", "CLI"] -[Configs.Debug.Linux64] +[Configs.Release.macOS] TargetDirectory = "$(WorkspaceDir)/../IDE/dist" -TargetName = "$(ProjectName)_d" -OtherLinkFlags = "./libBeefRT_d.so ./libIDEHelper_d.so ./libBeefySysLib_d.so ../../extern/llvm_linux_8_0_0/lib/libLLVMCore.a ../../extern/llvm_linux_8_0_0/lib/libLLVMMC.a ../../extern/llvm_linux_8_0_0/lib/libLLVMMCParser.a ../../extern/llvm_linux_8_0_0/lib/libLLVMCodeGen.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86Disassembler.a ../../extern/llvm_linux_8_0_0/lib/libLLVMMCDisassembler.a ../../extern/llvm_linux_8_0_0/lib/libLLVMSupport.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86Info.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86Utils.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86AsmPrinter.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86Desc.a ../../extern/llvm_linux_8_0_0/lib/libLLVMObject.a ../../extern/llvm_linux_8_0_0/lib/libLLVMBitReader.a ../../extern/llvm_linux_8_0_0/lib/libLLVMAsmParser.a ../../extern/llvm_linux_8_0_0/lib/libLLVMTarget.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86CodeGen.a ../../extern/llvm_linux_8_0_0/lib/libLLVMScalarOpts.a ../../extern/llvm_linux_8_0_0/lib/libLLVMInstCombine.a ../../extern/llvm_linux_8_0_0/lib/libLLVMSelectionDAG.a ../../extern/llvm_linux_8_0_0/lib/libLLVMProfileData.a ../../extern/llvm_linux_8_0_0/lib/libLLVMTransformUtils.a ../../extern/llvm_linux_8_0_0/lib/libLLVMAnalysis.a ../../extern/llvm_linux_8_0_0/lib/libLLVMX86AsmParser.a ../../extern/llvm_linux_8_0_0/lib/libLLVMAsmPrinter.a ../../extern/llvm_linux_8_0_0/lib/libLLVMBitWriter.a ../../extern/llvm_linux_8_0_0/lib/libLLVMVectorize.a ../../extern/llvm_linux_8_0_0/lib/libLLVMipo.a ../../extern/llvm_linux_8_0_0/lib/libLLVMInstrumentation.a ../../extern/llvm_linux_8_0_0/lib/libLLVMDebugInfoDWARF.a ../../extern/llvm_linux_8_0_0/lib/libLLVMDebugInfoPDB.a ../../extern/llvm_linux_8_0_0/lib/libLLVMDebugInfoCodeView.a ../../extern/llvm_linux_8_0_0/lib/libLLVMGlobalISel.a ../../extern/llvm_linux_8_0_0/lib/libLLVMBinaryFormat.a ../../extern/llvm_linux_8_0_0/lib/libLLVMDemangle.a -ltinfo -Wl,-rpath -Wl,$ORIGIN" +OtherLinkFlags = "./libBeefRT.dylib ./libIDEHelper.dylib ./libBeefySysLib.dylib ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMCore.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMMC.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMMCParser.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMCodeGen.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86Disassembler.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMMCDisassembler.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMSupport.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86Info.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86Utils.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86AsmPrinter.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86Desc.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMObject.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMBitReader.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMAsmParser.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMTarget.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86CodeGen.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMScalarOpts.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMInstCombine.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMSelectionDAG.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMProfileData.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMTransformUtils.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMAnalysis.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMX86AsmParser.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMAsmPrinter.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMBitWriter.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMVectorize.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMipo.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMInstrumentation.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMDebugInfoDWARF.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMDebugInfoPDB.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMDebugInfoCodeView.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMGlobalISel.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMBinaryFormat.a ../../extern/llvm_linux_rel_8_0_0/lib/libLLVMDemangle.a -Wl,-rpath -Wl,." CLibType = "Dynamic" DebugCommandArguments = "-proddir=..\\ -config=Debug -platform=Win64" DebugWorkingDirectory = "$(WorkspaceDir)/../IDE/dist" -PreprocessorMacros = ["DEBUG", "CLI"] +PreprocessorMacros = ["CLI"] [Configs.Release.Linux64] TargetDirectory = "$(WorkspaceDir)/../IDE/dist" diff --git a/BeefRT/CMakeLists.txt b/BeefRT/CMakeLists.txt index 35520bace..a779ba472 100644 --- a/BeefRT/CMakeLists.txt +++ b/BeefRT/CMakeLists.txt @@ -50,6 +50,68 @@ if (${APPLE}) ../BeefySysLib/platform/osx ) +elseif (${ANDROID}) + if (ANDROID_ABI STREQUAL "x86") + include_directories( + . + ../BeefySysLib/ + ../BeefySysLib/third_party + ../BeefySysLib/third_party/freetype/include + ../BeefySysLib/third_party/libffi/i686-pc-linux-gnu/include + ../ + ../extern + ../extern/llvm/include + ../extern/llvm_linux/include + ../extern/llvm/lib/Target + + ../BeefySysLib/platform/android + ) + elseif (ANDROID_ABI STREQUAL "x86_64") + include_directories( + . + ../BeefySysLib/ + ../BeefySysLib/third_party + ../BeefySysLib/third_party/freetype/include + ../BeefySysLib/third_party/libffi/x86_64-pc-linux-gnu/include + ../ + ../extern + ../extern/llvm/include + ../extern/llvm_linux/include + ../extern/llvm/lib/Target + + ../BeefySysLib/platform/android + ) + elseif (ANDROID_ABI STREQUAL "armeabi-v7a") + include_directories( + . + ../BeefySysLib/ + ../BeefySysLib/third_party + ../BeefySysLib/third_party/freetype/include + ../BeefySysLib/third_party/libffi/arm-unknown-linux-gnu/include + ../ + ../extern + ../extern/llvm/include + ../extern/llvm_linux/include + ../extern/llvm/lib/Target + + ../BeefySysLib/platform/android + ) + else() + include_directories( + . + ../BeefySysLib/ + ../BeefySysLib/third_party + ../BeefySysLib/third_party/freetype/include + ../BeefySysLib/third_party/libffi/aarch64-unknown-linux-gnu/include + ../ + ../extern + ../extern/llvm/include + ../extern/llvm_linux/include + ../extern/llvm/lib/Target + + ../BeefySysLib/platform/android + ) + endif() else() include_directories( . @@ -135,6 +197,7 @@ file(GLOB SRC_FILES ../BeefySysLib/util/BeefPerf.cpp ../BeefySysLib/util/String.cpp ../BeefySysLib/util/UTF8.cpp + ../BeefySysLib/util/Hash.cpp ../BeefySysLib/third_party/utf8proc/utf8proc.c ) @@ -143,6 +206,11 @@ if (${APPLE}) ../BeefySysLib/platform/darwin/BFPlatform.cpp ../BeefySysLib/platform/darwin/DarwinCommon.cpp ) +elseif (${ANDROID}) + file(GLOB SRC_FILES_OS + ../BeefySysLib/platform/android/BFPlatform.cpp + ../BeefySysLib/platform/android/AndroidCommon.cpp + ) else() file(GLOB SRC_FILES_OS ../BeefySysLib/platform/linux/BFPlatform.cpp @@ -151,15 +219,19 @@ else() endif() # Add library to build. -add_library(${PROJECT_NAME} SHARED +add_library(${PROJECT_NAME} STATIC ${SRC_FILES} ${SRC_FILES_OS} ) if (${APPLE}) - set(TARGET_LIBS_OS "") + target_link_libraries(${PROJECT_NAME} pthread ffi) +elseif (${ANDROID}) + set(TARGET_LIBS_OS "") + #target_link_libraries(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/../BeefySysLib/third_party/libffi/aarch64-unknown-linux-gnu/.libs/libffi.a) + #target_link_libraries(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/../BeefySysLib/third_party/libffi/i686-pc-linux-gnu/.libs/libffi.a) else() - set(TARGET_LIBS_OS "backtrace") + target_link_libraries(${PROJECT_NAME} pthread ffi backtrace) endif() # Link with other dependencies. @@ -167,6 +239,8 @@ if(MSVC) target_link_libraries(${PROJECT_NAME} BeefySysLib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib LLVMX86Disassembler.lib LLVMMCDisassembler.lib LLVMSupport.lib LLVMX86Info.lib LLVMX86Utils.lib LLVMX86AsmPrinter.lib LLVMX86Desc.lib %(AdditionalDependencies) LLVMMC.lib LLVMObject.lib LLVMCore.lib LLVMBitReader.lib LLVMAsmParser.lib LLVMMCParser.lib LLVMCodeGen.lib LLVMTarget.lib LLVMX86CodeGen.lib LLVMScalarOpts.lib LLVMInstCombine.lib LLVMSelectionDAG.lib LLVMProfileData.lib LLVMTransformUtils.lib LLVMAnalysis.lib LLVMX86AsmParser.lib LLVMAsmPrinter.lib LLVMBitWriter.lib LLVMVectorize.lib LLVMipo.lib LLVMInstrumentation.lib LLVMDebugInfoDWARF.lib LLVMDebugInfoPDB.lib LLVMDebugInfoCodeView.lib LLVMGlobalISel.lib LLVMBinaryFormat.lib libcurl_a.lib) else() set(LLVM_LIB "${CMAKE_CURRENT_SOURCE_DIR}/../extern/llvm_linux/lib") - target_link_libraries(${PROJECT_NAME} BeefySysLib pthread dl ffi ${TARGET_LIBS_OS} + target_link_libraries(${PROJECT_NAME} dl ) endif() + +#pthread ffi \ No newline at end of file diff --git a/BeefRT/rt/Internal.cpp b/BeefRT/rt/Internal.cpp index b5ef22349..d2841b8ca 100644 --- a/BeefRT/rt/Internal.cpp +++ b/BeefRT/rt/Internal.cpp @@ -230,9 +230,9 @@ void SetErrorString(const char* str) while (true) { const char* prevStr = gErrorString; - auto result = ::InterlockedCompareExchangePointer((void* volatile*)&gErrorString, (void*)newStr, (void*)prevStr); + auto result = (void*)BfpSystem_InterlockedCompareExchangePtr((uintptr*)&gErrorString, (uintptr)prevStr, (uintptr)newStr); if (result != prevStr) - continue; + continue; if (prevStr != NULL) free((void*)prevStr); break; diff --git a/BeefySysLib/platform/android/AndroidCommon.cpp b/BeefySysLib/platform/android/AndroidCommon.cpp new file mode 100644 index 000000000..8d0e6a96c --- /dev/null +++ b/BeefySysLib/platform/android/AndroidCommon.cpp @@ -0,0 +1,8 @@ +#include + +#define BFP_PRINTF(...) __android_log_print(ANDROID_LOG_INFO, "Beef", __VA_ARGS__) +#define BFP_ERRPRINTF(...) __android_log_print(ANDROID_LOG_ERROR, "Beef", __VA_ARGS__) + +#define BFP_HAS_PTHREAD_GETATTR_NP + +#include "../posix/PosixCommon.cpp" \ No newline at end of file diff --git a/BeefySysLib/platform/android/AndroidCommon.h b/BeefySysLib/platform/android/AndroidCommon.h new file mode 100644 index 000000000..462480945 --- /dev/null +++ b/BeefySysLib/platform/android/AndroidCommon.h @@ -0,0 +1,159 @@ +#pragma once + +#ifdef __LP64__ +#define BF64 +#else +#define BF32 +#endif + +#define BOOST_DETAIL_NO_CONTAINER_FWD + +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#define offsetof(type, member) __builtin_offsetof (type, member) + +extern "C" +{ +//#define FFI_BUILDING +//#include "third_party/libffi/x86_64-apple-darwin12.5.0/include/ffi.h" +} + +#define BF_ENDIAN_LITTLE + +#define _NOEXCEPT noexcept +#define NTAPI + +//#define FFI_STDCALL FFI_DEFAULT_ABI +//#define FFI_THISCALL FFI_DEFAULT_ABI +//#define FFI_FASTCALL FFI_DEFAULT_ABI + +#define INVALID_SOCKET -1 + +typedef uint64_t uint64; +typedef uint32_t uint32; +typedef uint16_t uint16; +typedef uint8_t uint8; +typedef int64_t int64; +typedef int32_t int32; +typedef int16_t int16; +typedef int8_t int8; +typedef unsigned int uint; + +//#define BF_PLATFORM_SDL + +#define NOP +//#define BF_NOTHROW throw () +//#define BF_NOTHROW noexcept +#define BF_NOTHROW + +#ifdef BF64 +typedef int64 intptr; +typedef uint64 uintptr; +#else +typedef int32 intptr; +typedef uint32 uintptr; +#endif + +typedef wchar_t* BSTR; +typedef int HRESULT; +typedef uint8 BYTE; +typedef uint16 WORD; +typedef uint32 DWORD; +typedef int32 LONG; + +typedef pthread_key_t BFTlsKey; +typedef pthread_t BF_THREADID; +typedef pthread_t BF_THREADHANDLE; + +#define BF_HAS_TLS_DECLSPEC +#define BF_TLS_DECLSPEC thread_local + +//:int64 abs(int64 val); + +#define _stricmp stricmp +#define strnicmp strncasecmp + +struct IID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[ 8 ]; +}; + +typedef void* HANDLE; +typedef void* HMODULE; + +// We only need the stdcall attribute for x32? +//#define BFSTDCALL __attribute__((stdcall)) + +//#include "../notwin/NotWin.h" + +#ifdef DEBUG +#define _DEBUG +#endif + +#define NOT_IMPL throw "Unimplemented"; + +//ARM + +#if defined(__x86_64__) || defined(__i386__) +#define BF_FULL_MEMORY_FENCE() __asm__ __volatile__("mfence": : :"memory") +#define BF_SPINWAIT_NOP() __asm__ volatile ("pause\n" : : : "memory" ); +#else +#define BF_FULL_MEMORY_FENCE() __sync_synchronize() +#define BF_SPINWAIT_NOP() ((void) 0) +#endif + +#define BF_COMPILER_FENCE() __asm__ __volatile__("": : :"memory") +#define BF_THREAD_YIELD() sched_yield() + +#if defined _DEBUG || defined BF_DEBUG_ASSERTS +#define BF_ASSERT(_Expression) (void)( (!!(_Expression)) || (Beefy::BFFatalError(#_Expression, __FILE__, __LINE__), 0) ) +#else +#define BF_ASSERT(_Expression) (void)(0) +#endif + +#define BF_ASSERT_REL(_Expression) (void)( (!!(_Expression)) || (Beefy::BFFatalError(#_Expression, __FILE__, __LINE__), 0) ) +#define BF_FATAL(msg) (void) ((Beefy::BFFatalError(msg, __FILE__, __LINE__), 0) ) + +#if defined _DEBUG || defined BF_DEBUG_ASSERTS +#define BF_DBG_FATAL(msg) (void) ((Beefy::BFFatalError(msg, __FILE__, __LINE__), 0) ) +#else +#define BF_DBG_FATAL(msg) +#endif + +#define BF_NOINLINE __attribute__ ((noinline)) +#define BF_NAKED + +#define stricmp strcasecmp +#define _alloca alloca + +#define DIR_SEP_CHAR '/' +#define DIR_SEP_CHAR_ALT '\\' + +static char* itoa(int value, char* str, int base) +{ + if (base == 16) + sprintf(str, "%X", value); + else + sprintf(str, "%d", value); + return str; +} diff --git a/BeefySysLib/platform/android/BFPlatform.cpp b/BeefySysLib/platform/android/BFPlatform.cpp new file mode 100644 index 000000000..8828d289d --- /dev/null +++ b/BeefySysLib/platform/android/BFPlatform.cpp @@ -0,0 +1,13 @@ +#include "Common.h" +#include "BFPlatform.h" +//#include +//#include +#include +#include +#include +#include +//#include +//#include +#include +#include + diff --git a/BeefySysLib/platform/android/BFPlatform.h b/BeefySysLib/platform/android/BFPlatform.h new file mode 100644 index 000000000..234dadc55 --- /dev/null +++ b/BeefySysLib/platform/android/BFPlatform.h @@ -0,0 +1,24 @@ +#pragma once + +#define BFSTDCALL + +#include "AndroidCommon.h" + +#define BF_PLATFORM_ANDROID +#define BF_PLATFORM_POSIX +#define BF_PLATFORM_NAME "BF_PLATFORM_ANDROID" + +#define BF_IMPORT extern "C" + +#ifdef BFSYSLIB_DYNAMIC +#define BF_EXPORT extern "C" +#define BF_CALLTYPE +#else +#define BF_EXPORT extern "C" +#define BF_CALLTYPE +#define BF_RESOURCES_REL_DIR "../Resources" +#endif + +#define BF_DEBUG_BREAK() + +#include "../PlatformInterface.h" diff --git a/BeefySysLib/platform/android/PlatformApp.h b/BeefySysLib/platform/android/PlatformApp.h new file mode 100644 index 000000000..bc255f1af --- /dev/null +++ b/BeefySysLib/platform/android/PlatformApp.h @@ -0,0 +1,9 @@ +#pragma once + +#include "../../HeadlessApp.h" + +NS_BF_BEGIN; + +typedef HeadlessApp PlatformBFApp; + +NS_BF_END; \ No newline at end of file diff --git a/BeefySysLib/platform/darwin/DarwinCommon.cpp b/BeefySysLib/platform/darwin/DarwinCommon.cpp index 15e7eaf7b..d16b3445b 100644 --- a/BeefySysLib/platform/darwin/DarwinCommon.cpp +++ b/BeefySysLib/platform/darwin/DarwinCommon.cpp @@ -1,3296 +1,9 @@ -#include "Common.h" -#include "BFPlatform.h" -#include +#include #include -#include -#include -#include -#include -#include -//#include #include -#include -#include -#include -#include -#include -#include -#include "../PlatformInterface.h" -#include "../PlatformHelper.h" -#include "../util/CritSect.h" -#include "../util/Dictionary.h" -#include "../util/Hash.h" -#include -//#include "backtrace.h" -//#include "backtrace-supported.h" -#include "../third_party/stb/stb_sprintf.h" -#include -#include - #include -USING_NS_BF; - - -struct BfpPipeInfo -{ - String mPipePath; - int mWriteHandle; -}; - -struct BfpFile -{ - BfpPipeInfo* mPipeInfo; - int mHandle; - bool mNonBlocking; - bool mAllowTimeout; - bool mIsStd; - - BfpFile() - { - mPipeInfo = NULL; - mHandle = -1; - mNonBlocking = false; - mAllowTimeout = false; - mIsStd = false; - } - - BfpFile(int handle) - { - mPipeInfo = NULL; - mHandle = handle; - mNonBlocking = false; - mAllowTimeout = false; - mIsStd = false; - } - - ~BfpFile() - { - delete mPipeInfo; - } -}; - -BfpTimeStamp BfpToTimeStamp(const timespec& ts) -{ - return (int64)(ts.tv_sec * 10000000) + (int64)(ts.tv_nsec / 100) + 116444736000000000; -} - -int gBFPlatformLastError = 0; - -uint32 Beefy::BFTickCount() -{ - struct timespec now; - if (clock_gettime(CLOCK_MONOTONIC, &now)) - return 0; - return (uint32)((uint64)now.tv_sec * 1000.0 + (uint64)now.tv_nsec / 1000000); -} - -int64 Beefy::EndianSwap(int64 val) -{ - return __builtin_bswap64(val); -} - -/*int* GetStdHandle(int32 handleId) -{ - if (handleId == STD_INPUT_HANDLE) - return (int*)STDIN_FILENO; - if (handleId == STD_OUTPUT_HANDLE) - return (int*)STDOUT_FILENO; - return (int*)STDERR_FILENO; -}*/ - -/*int32 GetFileType(HANDLE fileHandle) -{ - if (isatty(file->mHandleHandle)) - return FILE_TYPE_CHAR; - return FILE_TYPE_DISK; -}*/ - -/*bool WriteFile(HANDLE hFile, void* lpBuffer, uint32 nNumberOfBytesToWrite, uint32* lpNumberOfBytesWritten, OVERLAPPED* lpOverlapped) -{ -#ifdef BF_PLATFORM_IOS - int logType = -1; - if (hFile == (int*)STDOUT_FILENO) - logType = LOG_WARNING; - else if (hFile == (int*)STDERR_FILENO) - logType = LOG_ERR; - - if (logType != -1) - { - static std::string strOut; - strOut.resize(nNumberOfBytesToWrite); - memcpy(&strOut[0], lpBuffer, nNumberOfBytesToWrite); - if ((strOut[0] != '\r') && (strOut[0] != '\n')) - syslog(LOG_WARNING, "%s", strOut.c_str()); - } -#endif - - int writeCount = (int)::write((int)(intptr)hFile, lpBuffer, nNumberOfBytesToWrite); - if (writeCount == -1) - { - //TODO: set gBFPlatformLastError - lpNumberOfBytesWritten = 0; - return false; - } - - *lpNumberOfBytesWritten = (uint32)writeCount; - return true; -}*/ - -int64 Beefy::GetFileTimeWrite(const StringImpl& path) -{ - struct stat statbuf = {0}; - int result = stat(path.c_str(), &statbuf); - if (result == -1) - return 0; - - //int64 fileTime = 0; - //BFSystemTimeToFileTime(statbuf.st_mtime, 0, &fileTime); - return statbuf.st_mtime; -} - -/*DWORD GetTimeZoneInformation(TIME_ZONE_INFORMATION* lpTimeZoneInformation) -{ - std::wstring tzName0 = Beefy::UTF8Decode(tzname[0]); - std::wstring tzName1 = Beefy::UTF8Decode(tzname[1]); - - bool isDST = false; - - time_t timeNow; - time(&timeNow); - tm tmNow = *gmtime(&timeNow); - isDST = tmNow.tm_isdst; - - struct tm checkTM; - memset(&checkTM, 0, sizeof(tm)); - checkTM.tm_mday = 1; - checkTM.tm_year = tmNow.tm_year; - time_t checkTime = mktime(&checkTM); - - time_t lastOffset = 0; - time_t minOffset = 0; - time_t maxOffset = 0; - - for (int pass = 0; pass < 2; pass++) - { - int searchDir = 60*60*24; - int thresholdCount = 0; - - while (true) - { - checkTime += searchDir; - - tm checkTM = *gmtime(&checkTime); - - if (checkTM.tm_year != tmNow.tm_year) - break; // No DST - - mktime(&checkTM); - - time_t offset = checkTM.tm_gmtoff; - if (lastOffset != offset) - { - if (thresholdCount == 0) - { - minOffset = offset; - maxOffset = offset; - } - else if (thresholdCount == 3) - { - SYSTEMTIME* sysTimeP = (offset == minOffset) ? - &lpTimeZoneInformation->StandardDate : - &lpTimeZoneInformation->DaylightDate; - - if (offset == minOffset) - tzName0 = Beefy::UTF8Decode(checkTM.tm_zone); - else - tzName1 = Beefy::UTF8Decode(checkTM.tm_zone); - - sysTimeP->wDay = 0; - sysTimeP->wDayOfWeek = 0; - sysTimeP->wYear = checkTM.tm_year + 1900; - sysTimeP->wMonth = checkTM.tm_mon; - sysTimeP->wDay = checkTM.tm_mday + 1; - sysTimeP->wHour = checkTM.tm_hour; - sysTimeP->wMinute = checkTM.tm_min; - sysTimeP->wSecond = checkTM.tm_sec; - sysTimeP->wMilliseconds = 0; - - break; - } - else - { - if (thresholdCount == 1) - searchDir /= -24; - else - searchDir /= -60; - minOffset = std::min(minOffset, offset); - maxOffset = std::max(maxOffset, offset); - } - thresholdCount++; - lastOffset = offset; - } - } - } - - wcsncpy(lpTimeZoneInformation->StandardName, tzName0.c_str(), 32); - wcsncpy(lpTimeZoneInformation->DaylightName, tzName1.c_str(), 32); - - lpTimeZoneInformation->DaylightBias = (int32)maxOffset; - lpTimeZoneInformation->StandardBias = (int32)minOffset; - - if (minOffset == maxOffset) - return 0; - return isDST ? 2 : 1; -}*/ - -bool Beefy::FileExists(const StringImpl& path, String* outActualName) -{ - struct stat statbuf = {0}; - int result = stat(path.c_str(), &statbuf); - if (result != 0) - return false; - return !S_ISDIR(statbuf.st_mode); -} - -bool Beefy::DirectoryExists(const StringImpl& path, String* outActualName) -{ - struct stat statbuf = {0}; - int result = stat(path.c_str(), &statbuf); - if (result != 0) - return false; - return S_ISDIR(statbuf.st_mode); -} - -uint64 Beefy::BFGetTickCountMicro() -{ - struct timespec now; - if (clock_gettime(CLOCK_MONOTONIC, &now)) - return 0; - return ((uint64)now.tv_sec * 1000000.0 + (uint64)now.tv_nsec / 1000); -} - -uint64 Beefy::BFGetTickCountMicroFast() -{ - return BFGetTickCountMicro(); -} - -/* -int64 abs(int64 val) -{ - return llabs(val); -} -*/ -void mkdir(const char* path) -{ - mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); -} - -typedef void(*CrashInfoFunc)(); - -static CritSect gSysCritSect; -static String gCrashInfo; -static Array gCrashInfoFuncs; - -static String gCmdLine; -static String gExePath; - -typedef struct _Unwind_Context _Unwind_Context; // opaque - -typedef enum { - _URC_NO_REASON = 0, - _URC_OK = 0, - _URC_FOREIGN_EXCEPTION_CAUGHT = 1, - _URC_FATAL_PHASE2_ERROR = 2, - _URC_FATAL_PHASE1_ERROR = 3, - _URC_NORMAL_STOP = 4, - _URC_END_OF_STACK = 5, - _URC_HANDLER_FOUND = 6, - _URC_INSTALL_CONTEXT = 7, - _URC_CONTINUE_UNWIND = 8, - _URC_FAILURE = 9 -} _Unwind_Reason_Code; - -typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, void *); -extern "C" _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *); -extern "C" uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); - -static String gUnwindExecStr; -static int gUnwindIdx = 0; - -static _Unwind_Reason_Code UnwindHandler(struct _Unwind_Context* context, void* ref) -{ - gUnwindIdx++; - if (gUnwindIdx < 2) - return _URC_NO_REASON; - - dl_info dyldInfo; - void* addr = (void*)_Unwind_GetIP(context); - gUnwindExecStr += StrFormat(" %p", addr); - return _URC_NO_REASON; -} - -static bool FancyBacktrace() -{ - gUnwindExecStr += StrFormat("atos -p %d", getpid()); - _Unwind_Backtrace(&UnwindHandler, NULL); - return system(gUnwindExecStr.c_str()) == 0; -} - -static void Crashed() -{ - // - { - AutoCrit autoCrit(gSysCritSect); - - String debugDump; - - debugDump += "**** FATAL APPLICATION ERROR ****\n"; - - for (auto func : gCrashInfoFuncs) - func(); - - if (!gCrashInfo.IsEmpty()) - { - debugDump += gCrashInfo; - debugDump += "\n"; - } - - fprintf(stderr, "%s", debugDump.c_str()); - } - - if (!FancyBacktrace()) - { - void* array[64]; - size_t size; - char** strings; - size_t i; - - size = backtrace(array, 64); - strings = backtrace_symbols(array, size); - - for (i = 0; i < size; i++) - fprintf(stderr, "%s\n", strings[i]); - - free(strings); - } - - exit(1); -} - -static void SigHandler(int sig) -{ - //printf("SigHandler paused...\n"); - - const char* sigName = NULL; - switch (sig) - { - case SIGFPE: - sigName = "SIGFPE"; - break; - case SIGSEGV: - sigName = "SIGSEGV"; - break; - case SIGABRT: - sigName = "SIGABRT"; - break; - case SIGILL: - sigName = "SIGILL"; - break; - } - - if (sigName != NULL) - gCrashInfo += StrFormat("Signal: %s\n", sigName); - else - gCrashInfo += StrFormat("Signal: %d\n", sig); - Crashed(); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_Init(int version, BfpSystemInitFlags flags) -{ - if (version != BFP_VERSION) - { - BfpSystem_FatalError(StrFormat("Bfp build version '%d' does not match requested version '%d'", BFP_VERSION, version).c_str(), "BFP FATAL ERROR"); - } - - signal(SIGSEGV, SigHandler); - signal(SIGFPE, SigHandler); - signal(SIGABRT, SigHandler); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCommandLine(int argc, char** argv) -{ - char* relPath = argv[0]; - - char* cwd = getcwd(NULL, 0); - gExePath = GetAbsPath(relPath, cwd); - - free(cwd); - - for (int i = 0; i < argc; i++) - { - if (i != 0) - gCmdLine.Append(' '); - - String arg = argv[i]; - if ((arg.Contains(' ')) || (arg.Contains('\"'))) - { - arg.Replace("\"", "\\\""); - gCmdLine.Append("\""); - gCmdLine.Append(arg); - gCmdLine.Append("\""); - } - else - gCmdLine.Append(arg); - } -} - - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCrashReportKind(BfpCrashReportKind crashReportKind) -{ - -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfoFunc(BfpCrashInfoFunc crashInfoFunc) -{ - AutoCrit autoCrit(gSysCritSect); - gCrashInfoFuncs.Add(crashInfoFunc); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfo(const char* str) // Can do at any time, or during CrashInfoFunc callbacks -{ - AutoCrit autoCrit(gSysCritSect); - gCrashInfo.Append(str); -} - -void BfpSystem_Shutdown() -{ - -} - -BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_TickCount() -{ - return Beefy::BFTickCount(); -} - -BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpSystem_GetTimeStamp() -{ - struct timeval tv; - BfpTimeStamp result = 11644473600LL; - gettimeofday(&tv, NULL); - result += tv.tv_sec; - result *= 10000000LL; - result += tv.tv_usec * 10; - return result; -} - -BFP_EXPORT uint16 BFP_CALLTYPE BfpSystem_EndianSwap16(uint16 val) -{ - return __builtin_bswap16(val); -} - -BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_EndianSwap32(uint32 val) -{ - return __builtin_bswap32(val); -} - -BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_EndianSwap64(uint64 val) -{ - return __builtin_bswap64(val); -} - -BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedExchange32(uint32* ptr, uint32 val) -{ - // __sync_lock_test_and_set only has Acquire semantics, so we need a __sync_synchronize to enforce a full barrier - uint32 prevVal = __sync_lock_test_and_set(ptr, val); - __sync_synchronize(); - return prevVal; -} - -BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedExchange64(uint64* ptr, uint64 val) -{ - // __sync_lock_test_and_set only has Acquire semantics, so we need a __sync_synchronize to enforce a full barrier - uint64 prevVal = __sync_lock_test_and_set(ptr, val); - __sync_synchronize(); - return prevVal; -} - -BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedExchangeAdd32(uint32* ptr, uint32 val) -{ - return __sync_fetch_and_add(ptr, val); -} - -BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedExchangeAdd64(uint64* ptr, uint64 val) -{ - return __sync_fetch_and_add(ptr, val); -} - -BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedCompareExchange32(uint32* ptr, uint32 oldVal, uint32 newVal) -{ - return __sync_val_compare_and_swap(ptr, oldVal, newVal); -} - -BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedCompareExchange64(uint64* ptr, uint64 oldVal, uint64 newVal) -{ - return __sync_val_compare_and_swap(ptr, oldVal, newVal); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_FatalError(const char* error, const char* title) -{ - fprintf(stderr, "%s\n", error); - fflush(stderr); - Crashed(); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetCommandLine(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) -{ - TryStringOut(gCmdLine, outStr, inOutStrSize, (BfpResult*)outResult); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetExecutablePath(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) -{ - //printf("Setting BfpSystem_GetExecutablePath %s %p\n", gExePath.c_str(), &gExePath); - - if (gExePath.IsEmpty()) - { - char path[4096]; - uint32_t size = sizeof(path); - if (_NSGetExecutablePath(path, &size) == 0) - gExePath = path; - - // When when running with a './file', we end up with an annoying '/./' in our path - gExePath.Replace("/./", "/"); - } - - TryStringOut(gExePath, outStr, inOutStrSize, (BfpResult*)outResult); -} - -extern char **environ; - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetEnvironmentStrings(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) -{ - String env; - - char** envPtr = environ; - while (true) - { - char* envStr = *envPtr; - env.Append(envStr, strlen(envStr) + 1); - ++envPtr; - } - - TryStringOut(env, outStr, inOutStrSize, (BfpResult*)outResult); -} - -BFP_EXPORT int BFP_CALLTYPE BfpSystem_GetNumLogicalCPUs(BfpSystemResult* outResult) -{ - OUTRESULT(BfpSystemResult_Ok); - int count = 1; - size_t count_len = sizeof(count); - sysctlbyname("hw.logicalcpu", &count, &count_len, NULL, 0); - return count; -} - -BFP_EXPORT int64 BFP_CALLTYPE BfpSystem_GetCPUTick() -{ - return 10000000; -} - -BFP_EXPORT int64 BFP_CALLTYPE BfpSystem_GetCPUTickFreq() -{ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - return (now.tv_sec * 10000000LL) + now.tv_nsec / 100; -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_CreateGUID(BfpGUID* outGuid) -{ -// uuid_t guid; -// uuid_generate(guid); -// BfpGUID bfpGuid; -// memcpy(&bfpGuid, guid, 16); -// return bfpGuid; - - uint8* ptr = (uint8*)outGuid; - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution dis(0, 255); - for (int i = 0; i < 16; i++) - ptr[i] = dis(gen); - - // variant must be 10xxxxxx - ptr[8] &= 0xBF; - ptr[8] |= 0x80; - - // version must be 0100xxxx - ptr[6] &= 0x4F; - ptr[6] |= 0x40; -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetComputerName(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) -{ - char hostName[1024]; - gethostname(hostName, 1024); - TryStringOut(hostName, outStr, inOutStrSize, (BfpResult*)outResult); -} - -// BfpProcess - -BFP_EXPORT intptr BFP_CALLTYPE BfpProcess_GetCurrentId() -{ - return getpid(); -} - -BFP_EXPORT bool BFP_CALLTYPE BfpProcess_IsRemoteMachine(const char* machineName) -{ - return false; -} - -BFP_EXPORT BfpProcess* BFP_CALLTYPE BfpProcess_GetById(const char* machineName, int processId, BfpProcessResult* outResult) -{ - NOT_IMPL; - return NULL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpProcess_Enumerate(const char* machineName, BfpProcess** outProcesses, int* inOutProcessesSize, BfpProcessResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpProcess_Release(BfpProcess* process) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpProcess_GetMainWindowTitle(BfpProcess* process, char* outTitle, int* inOutTitleSize, BfpProcessResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpProcess_GetProcessName(BfpProcess* process, char* outName, int* inOutNameSize, BfpProcessResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT int BFP_CALLTYPE BfpProcess_GetProcessId(BfpProcess* process) -{ - NOT_IMPL; - return 0; -} - -// BfpSpawn - -struct BfpSpawn -{ - int mPid; - bool mExited; - int mStatus; - int mStdInFD; - int mStdOutFD; - int mStdErrFD; -}; - -BFP_EXPORT BfpSpawn* BFP_CALLTYPE BfpSpawn_Create(const char* inTargetPath, const char* args, const char* workingDir, const char* env, BfpSpawnFlags flags, BfpSpawnResult* outResult) -{ - Beefy::Array stringViews; - - //printf("Executing: %s %s %x\n", inTargetPath, args, flags); - - if ((workingDir != NULL) && (workingDir[0] != 0)) - { - if (chdir(workingDir) != 0) - { - //printf("CHDIR failed %s\n", workingDir); - OUTRESULT(BfpSpawnResult_UnknownError); - return NULL; - } - } - - String newArgs; - String tempFileName; - - if ((flags & BfpSpawnFlag_UseArgsFile) != 0) - { - char tempFileNameStr[256]; - int size = 256; - BfpFileResult fileResult; - BfpFile_GetTempFileName(tempFileNameStr, &size, &fileResult); - if (fileResult == BfpFileResult_Ok) - { - tempFileName = tempFileNameStr; - - BfpFileResult fileResult; - BfpFile* file = BfpFile_Create(tempFileNameStr, BfpFileCreateKind_CreateAlways, BfpFileCreateFlag_Write, BfpFileAttribute_Normal, &fileResult); - if (file == NULL) - { - OUTRESULT(BfpSpawnResult_TempFileError); - return NULL; - } - - if ((flags & BfpSpawnFlag_UseArgsFile_Native) != 0) - { - UTF16String wStr = UTF8Decode(args); - - if ((flags & BfpSpawnFlag_UseArgsFile_BOM) != 0) - { - uint8 bom[2] = { 0xFF, 0xFE }; - BfpFile_Write(file, bom, 2, -1, NULL); - } - - BfpFile_Write(file, wStr.c_str(), wStr.length() * 2, -1, NULL); - } - else - BfpFile_Write(file, args, strlen(args), -1, NULL); - BfpFile_Release(file); - - newArgs.Append("@"); - newArgs.Append(tempFileName); - if (newArgs.Contains(' ')) - { - newArgs.Insert(0, '\"'); - newArgs.Append('\"'); - } - - args = newArgs.c_str(); - } - } - - int32 firstCharIdx = -1; - bool inQuote = false; - - String targetPath = inTargetPath; - String verb; - if ((flags & BfpSpawnFlag_UseShellExecute) != 0) - { - String target = targetPath; - int barPos = (int)target.IndexOf('|'); - if (barPos != -1) - { - verb = targetPath.Substring(barPos + 1); - targetPath.RemoveToEnd(barPos); - } - } - - int32 i = 0; - for ( ; true; i++) - { - char c = args[i]; - if (c == '\0') - break; - if ((c == ' ') && (!inQuote)) - { - if (firstCharIdx != -1) - { - stringViews.Add(Beefy::StringView(args, firstCharIdx, i - firstCharIdx)); - firstCharIdx = -1; - } - } - else - { - if (firstCharIdx == -1) - firstCharIdx = i; - if (c == '"') - inQuote = !inQuote; - else if ((inQuote) && (c == '\\')) - { - c = args[i + 1]; - if (c == '"') - i++; - } - } - } - if (firstCharIdx != -1) - stringViews.Add(Beefy::StringView(args, firstCharIdx, i - firstCharIdx)); - - Beefy::Array argvArr; - - if ((flags & BfpSpawnFlag_ArgsIncludesTarget) == 0) - argvArr.Add(strdup(targetPath.c_str())); - - for (int32 i = 0; i < (int32)stringViews.size(); i++) - { - Beefy::StringView stringView = stringViews[i]; - char* str = NULL; - for (int32 pass = 0; pass < 2; pass++) - { - char* strPtr = str; - - int32 strPos = 0; - for (int32 char8Idx = 0; char8Idx < stringView.mLength; char8Idx++) - { - char c = stringView.mPtr[char8Idx]; - if (c == '"') - inQuote = !inQuote; - else - { - if ((inQuote) && (c == '\\') && (char8Idx < stringView.mLength - 1)) - { - char nextC = stringView.mPtr[char8Idx + 1]; - if (nextC == '"') - { - c = nextC; - char8Idx++; - } - } - if (strPtr != NULL) - *(strPtr++) = c; - strPos++; - } - } - if (pass == 0) - str = (char*)malloc(strPos + 1); - else - *(strPtr++) = 0; - } - - argvArr.Add(str); - } - argvArr.Add(NULL); - - char** argv = NULL; - - //pid_t pid = 0; - //int status = posix_spawn(&pid, targetPath, NULL, NULL, &argvArr[0], environ); - - Beefy::Array envArr; - if (env != NULL) - { - char* envPtr = (char*)env; - while (true) - { - if (*envPtr == 0) - break; - - envArr.Add(envPtr); - envPtr += strlen(envPtr) + 1; - } - } - envArr.Add(NULL); - - int stdInFD[2]; - int stdOutFD[2]; - int stdErrFD[2]; - - bool failed = false; - if ((flags & BfpSpawnFlag_RedirectStdInput) != 0) - if (pipe(stdInFD) != 0) - failed = true; - if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0) - if (pipe(stdOutFD) != 0) - failed = true; - if ((flags & BfpSpawnFlag_RedirectStdError) != 0) - if (pipe(stdErrFD) != 0) - failed = true; - if (failed) - { - //printf("Pipe failed\n"); - OUTRESULT(BfpSpawnResult_UnknownError); - return NULL; - } - - BfpSpawn* spawn; - pid_t pid = fork(); - if (pid == -1) // Error - { - OUTRESULT(BfpSpawnResult_UnknownError); - return NULL; - } - else if (pid == 0) // Child - { - if ((flags & BfpSpawnFlag_RedirectStdInput) != 0) - while ((dup2(stdInFD[0], STDIN_FILENO) == -1) && (errno == EINTR)) {} - if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0) - while ((dup2(stdOutFD[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {} - if ((flags & BfpSpawnFlag_RedirectStdError) != 0) - while ((dup2(stdErrFD[1], STDERR_FILENO) == -1) && (errno == EINTR)) {} - - // If successful then this shouldn't return at all: - int result; - - if (env != NULL) - result = execve(targetPath.c_str(), (char* const*)&argvArr[0], (char* const*)&envArr[0]); - else - result = execv(targetPath.c_str(), (char* const*)&argvArr[0]); - - printf("Couldn't execute %s\n", targetPath.c_str()); - - exit(-1); - } - else // Parent - { - spawn = new BfpSpawn(); - - if ((flags & BfpSpawnFlag_RedirectStdInput) != 0) - { - spawn->mStdInFD = stdInFD[1]; - close(stdInFD[0]); - } - else - spawn->mStdInFD = 0; - - if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0) - { - spawn->mStdOutFD = stdOutFD[0]; - close(stdOutFD[1]); - } - else - spawn->mStdOutFD = 0; - - if ((flags & BfpSpawnFlag_RedirectStdError) != 0) - { - spawn->mStdErrFD = stdErrFD[0]; - close(stdErrFD[1]); - } - else - spawn->mStdErrFD = 0; - } - - for (auto val : argvArr) - free(val); - - //printf("Spawn pid:%d status:%d\n", pid, status); - spawn->mPid = pid; - spawn->mExited = false; - spawn->mStatus = 0; - - return spawn; -} - -void BfpSpawn_Release(BfpSpawn* spawn) -{ - // We don't support 'detaching' currently- this can create zombie processes since we - // don't have a reaper strategy - BfpSpawn_WaitFor(spawn, -1, NULL, NULL); - - delete spawn; -} - -BFP_EXPORT void BFP_CALLTYPE BfpSpawn_GetStdHandles(BfpSpawn* spawn, BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr) -{ - if (outStdIn != NULL) - { - *outStdIn = new BfpFile(spawn->mStdInFD); - spawn->mStdInFD = 0; - } - - if (outStdOut != NULL) - { - *outStdOut = new BfpFile(spawn->mStdOutFD); - spawn->mStdOutFD = 0; - } - - if (outStdErr != NULL) - { - *outStdErr = new BfpFile(spawn->mStdErrFD); - spawn->mStdErrFD = 0; - } -} - -bool BfpSpawn_WaitFor(BfpSpawn* spawn, int waitMS, int* outExitCode, BfpSpawnResult* outResult) -{ - OUTRESULT(BfpSpawnResult_Ok); - if (!spawn->mExited) - { - int flags = 0; - if (waitMS != -1) - { - flags = WNOHANG; - } - //TODO: Implement values other than 0 or -1 for waitMS? - - pid_t result = waitpid(spawn->mPid, &spawn->mStatus, flags); - if (result != spawn->mPid) - return false; - - spawn->mExited = true; - } - - if (!WIFEXITED(spawn->mStatus) && !WIFSIGNALED(spawn->mStatus)) - return false; - - if (outExitCode != NULL) - *outExitCode = WEXITSTATUS(spawn->mStatus); - return true; -} - -// BfpFileWatcher - -BFP_EXPORT BfpFileWatcher* BFP_CALLTYPE BfpFileWatcher_WatchDirectory(const char* path, BfpDirectoryChangeFunc callback, BfpFileWatcherFlags flags, void* userData, BfpFileResult* outResult) -{ - NOT_IMPL; - return NULL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFileWatcher_Release(BfpFileWatcher* fileWatcher) -{ - NOT_IMPL; -} - -// BfpThread - -struct BfpThread -{ - bool mPThreadReleased; - BfpThreadStartProc mStartProc; - void* mThreadParam; - BfpEvent* mDoneEvent; - - pthread_t mPThread; - int mRefCount; - int mPriority; - - BfpThread() - { - } - - void Release() - { - int refCount = __sync_fetch_and_sub(&mRefCount, 1) - 1; - if (refCount == 0) - delete this; - } -}; - -struct BfpThreadInfo -{ - intptr mStackBase; - int mStackLimit; -}; - -static __thread BfpThread* gCurrentThread; -static __thread BfpThreadInfo gCurrentThreadInfo; - -void* ThreadFunc(void* threadParam) -{ - BfpThread* thread = (BfpThread*)threadParam; - gCurrentThread = thread; - thread->mStartProc(thread->mThreadParam); - BfpEvent_Set(thread->mDoneEvent, true); - thread->Release(); - return NULL; -} - -BFP_EXPORT BfpThread* BFP_CALLTYPE BfpThread_Create(BfpThreadStartProc startProc, void* threadParam, intptr stackSize, BfpThreadCreateFlags flags, BfpThreadId* outThreadId) -{ - BfpThread* thread = new BfpThread(); - thread->mPThreadReleased = false; - thread->mStartProc = startProc; - thread->mThreadParam = threadParam; - thread->mRefCount = 2; - thread->mPriority = 0; - thread->mDoneEvent = BfpEvent_Create(BfpEventFlag_None); - - BF_ASSERT(sizeof(pthread_t) <= sizeof(void*)); - pthread_attr_t params; - pthread_attr_init(¶ms); - pthread_attr_setstacksize(¶ms, stackSize); - //pthread_attr_setdetachstate(¶ms,PTHREAD_CREATE_DETACHED); - - pthread_create(&thread->mPThread, ¶ms, ThreadFunc, (void*)thread); - - pthread_attr_destroy(¶ms); - - if (outThreadId != NULL) - *outThreadId = (BfpThreadId)thread->mPThread; - - return thread; -} - -#define FIXTHREAD() \ - pthread_t pt; \ - if (((intptr)thread & 1) != 0) \ - { \ - pt = (pthread_t)((intptr)thread & ~3); \ - thread = NULL; \ - } else \ - pt = thread->mPThread - -BFP_EXPORT void BFP_CALLTYPE BfpThread_Release(BfpThread* thread) -{ - FIXTHREAD(); - if (thread == NULL) - return; - - BfpEvent_Release(thread->mDoneEvent); - if (!thread->mPThreadReleased) - { - pthread_detach(thread->mPThread); - thread->mPThreadReleased = true; - } - thread->Release(); -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_SetName(BfpThread* thread, const char* name, BfpThreadResult* outResult) -{ - OUTRESULT(BfpThreadResult_Ok); -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_GetName(BfpThread* thread, char* outName, int* inOutNameSize, BfpThreadResult* outResult) -{ - String str = ""; - TryStringOut(str, outName, inOutNameSize, (BfpResult*)outResult); -} - -BFP_EXPORT BfpThread* BFP_CALLTYPE BfpThread_GetCurrent() -{ - if (gCurrentThread == NULL) - { - // Not a "true" BfpThread, this is either the main thread or a thread we didn't create - return (BfpThread*)((intptr)pthread_self() | 1); - } - return gCurrentThread; -} - -BFP_EXPORT BfpThreadId BFP_CALLTYPE BfpThread_GetCurrentId() -{ - if (gCurrentThread == NULL) - { - return (BfpThreadId)((intptr)pthread_self()); - } - return (BfpThreadId)gCurrentThread->mPThread; -} - -BFP_EXPORT bool BFP_CALLTYPE BfpThread_WaitFor(BfpThread* thread, int waitMS) -{ - FIXTHREAD(); - - if (waitMS == -1) - { - pthread_join(pt, NULL); - thread->mPThreadReleased = true; - return true; - } - - if (thread == NULL) - BF_FATAL("Invalid thread with non-infinite wait"); - return BfpEvent_WaitFor(thread->mDoneEvent, waitMS); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSpawn_Kill(BfpSpawn* spawn, int exitCode, BfpKillFlags killFlags, BfpSpawnResult* outResult) -{ - //TODO: Implement - OUTRESULT(BfpSpawnResult_UnknownError); -} - -BFP_EXPORT BfpThreadPriority BFP_CALLTYPE BfpThread_GetPriority(BfpThread* thread, BfpThreadResult* outResult) -{ - FIXTHREAD(); - - OUTRESULT(BfpThreadResult_Ok); - if (thread == NULL) - return (BfpThreadPriority)0; - - return (BfpThreadPriority)thread->mPriority; -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_SetPriority(BfpThread* thread, BfpThreadPriority threadPriority, BfpThreadResult* outResult) -{ - // In effect, we have two 'nice' settings: 0 (normal) or 10 (low) - // High-priority settings just don't do anything - //pid_t tid = syscall(SYS_gettid); - //int ret = setpriority(PRIO_PROCESS, tid, -std::min(nPriority, 0) * 10); - OUTRESULT(BfpThreadResult_Ok); -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_Suspend(BfpThread* thread, BfpThreadResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_Resume(BfpThread* thread, BfpThreadResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_GetIntRegisters(BfpThread* thread, intptr* outStackPtr, intptr* outIntRegs, int* inOutIntRegCount, BfpThreadResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_GetStackInfo(BfpThread* thread, intptr* outStackBase, int* outStackLimit, BfpThreadResult* outResult) -{ - // USE mach_vm_region_info ?? - // https://github.com/dmlloyd/openjdk/blob/2f680fec58a8ffb818a48f542e493306d1113c69/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp#L902-L961 - - /*if (gCurrentThreadInfo.mStackBase == 0) - { - void* stackBase = 0; - size_t stackLimit = 0; - - pthread_attr_t attr; - pthread_getattr_np(pthread_self(), &attr); - pthread_attr_getstack(&attr, &stackBase, &stackLimit); - - gCurrentThreadInfo.mStackBase = (intptr)stackBase + stackLimit; - gCurrentThreadInfo.mStackLimit = (int)stackLimit; - pthread_attr_destroy(&attr); - } - - *outStackBase = gCurrentThreadInfo.mStackBase; - *outStackLimit = gCurrentThreadInfo.mStackLimit; - - OUTRESULT(BfpThreadResult_Ok);*/ - OUTRESULT(BfpThreadResult_UnknownError); -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_Sleep(int sleepMS) -{ - usleep(sleepMS * 1000); -} - -BFP_EXPORT bool BFP_CALLTYPE BfpThread_Yield() -{ - return sched_yield() == 0; -} - -struct BfpCritSect -{ - pthread_mutex_t mPMutex; -}; - -BFP_EXPORT BfpCritSect* BFP_CALLTYPE BfpCritSect_Create() -{ - BfpCritSect* critSect = new BfpCritSect(); - - pthread_mutexattr_t attributes; - pthread_mutexattr_init(&attributes); - pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&critSect->mPMutex, &attributes); - pthread_mutexattr_destroy(&attributes); - - return critSect; -} - -BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Release(BfpCritSect* critSect) -{ - pthread_mutex_destroy(&critSect->mPMutex); -} - -BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Enter(BfpCritSect* critSect) -{ - pthread_mutex_lock(&critSect->mPMutex); -} - -BFP_EXPORT bool BFP_CALLTYPE BfpCritSect_TryEnter(BfpCritSect* critSect, int waitMS) -{ - if (waitMS == -1) - { - BfpCritSect_Enter(critSect); - return true; - } - else if (waitMS == 0) - { - return pthread_mutex_trylock(&critSect->mPMutex) == 0; - } - - uint32 start = Beefy::BFTickCount(); - while ((int)(Beefy::BFTickCount() - start) < waitMS) - { - if (pthread_mutex_trylock(&critSect->mPMutex) == 0) - { - return true; - } - } - return false; -} - -BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Leave(BfpCritSect* critSect) -{ - pthread_mutex_unlock(&critSect->mPMutex); -} - -BFP_EXPORT BfpTLS* BFP_CALLTYPE BfpTLS_Create() -{ - pthread_key_t key = 0; - pthread_key_create(&key, NULL); - return (BfpTLS*)(intptr)key; -} - -BFP_EXPORT void BFP_CALLTYPE BfpTLS_Release(BfpTLS* tls) -{ - pthread_key_delete((pthread_key_t)(intptr)tls); -} - -BFP_EXPORT void BFP_CALLTYPE BfpTLS_SetValue(BfpTLS* tls, void* value) -{ - pthread_setspecific((pthread_key_t)(intptr)tls, value); -} - -BFP_EXPORT void* BFP_CALLTYPE BfpTLS_GetValue(BfpTLS* tls) -{ - return pthread_getspecific((pthread_key_t)(intptr)tls); -} - -struct BfpEvent -{ - pthread_mutex_t mMutex; - pthread_cond_t mCondVariable; - bool mSet; - bool mManualReset; -}; - -BFP_EXPORT BfpEvent* BFP_CALLTYPE BfpEvent_Create(BfpEventFlags flags) -{ - BfpEvent* event = new BfpEvent(); - pthread_mutex_init(&event->mMutex, NULL); - pthread_cond_init(&event->mCondVariable, NULL); - event->mSet = (flags & (BfpEventFlag_InitiallySet_Auto | BfpEventFlag_InitiallySet_Manual)) != 0; - event->mManualReset = (flags & BfpEventFlag_InitiallySet_Manual) != 0; - return event; -} - -BFP_EXPORT void BFP_CALLTYPE BfpEvent_Release(BfpEvent* event) -{ - pthread_cond_destroy(&event->mCondVariable); - pthread_mutex_destroy(&event->mMutex); -} - -BFP_EXPORT void BFP_CALLTYPE BfpEvent_Set(BfpEvent* event, bool requireManualReset) -{ - pthread_mutex_lock(&event->mMutex); - event->mSet = true; - if (requireManualReset) - event->mManualReset = true; - if (event->mManualReset) - pthread_cond_broadcast(&event->mCondVariable); - else - pthread_cond_signal(&event->mCondVariable); - pthread_mutex_unlock(&event->mMutex); -} - -BFP_EXPORT void BFP_CALLTYPE BfpEvent_Reset(BfpEvent* event, BfpEventResult* outResult) -{ - event->mSet = false; - event->mManualReset = false; -} - -BFP_EXPORT bool BFP_CALLTYPE BfpEvent_WaitFor(BfpEvent* event, int waitMS) -{ - int result = pthread_mutex_lock(&event->mMutex); - BF_ASSERT(result == 0); - while (!event->mSet) - { - if (waitMS == -1) - { - pthread_cond_wait(&event->mCondVariable, &event->mMutex); - } - else - { - timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += waitMS / 1000; - ts.tv_nsec += (waitMS % 1000) * 1000000; - - result = pthread_cond_timedwait(&event->mCondVariable, &event->mMutex, &ts); - - if (waitMS == (uint32)-1) - BF_ASSERT(result == 0); - - if (result != 0) - { - // Timeout - pthread_mutex_unlock(&event->mMutex); - return false; - } - } - } - if (!event->mManualReset) - event->mSet = false; - pthread_mutex_unlock(&event->mMutex); - return true; -} - -BFP_EXPORT BfpDynLib* BFP_CALLTYPE BfpDynLib_Load(const char* fileName) -{ - BfpDynLib* mod = NULL; - - static const char* prefixes[] = {NULL, "lib"}; - static const char* suffixes[] = {NULL, ".so", ".dylib"}; - - for (int prefixIdx = 0; prefixIdx < sizeof(prefixes)/sizeof(prefixes[0]); prefixIdx++) - { - for (int suffixIdx = 0; suffixIdx < sizeof(suffixes)/sizeof(suffixes[0]); suffixIdx++) - { - const char* prefix = prefixes[prefixIdx]; - const char* suffix = suffixes[suffixIdx]; - - Beefy::String checkName = fileName; - if (prefix != NULL) - checkName = Beefy::String(prefix) + checkName; - if (suffix != NULL) - { - int dotPos = checkName.LastIndexOf('.'); - if (dotPos != -1) - checkName.RemoveToEnd(dotPos); - checkName += suffix; - } - - mod = (BfpDynLib*)dlopen(checkName.c_str(), RTLD_LAZY); - if (mod != NULL) - return mod; - } - } - - /*mod = (BfpDynLib*)dlopen("/var/Beef/qt-build/Debug/bin/libIDEHelper.so", RTLD_LAZY);; - if (mod == NULL) - { - printf("Err: %s\n", dlerror()); - fflush(stdout); - }*/ - - return NULL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpDynLib_Release(BfpDynLib* lib) -{ - dlclose((void*)lib); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDynLib_GetFilePath(BfpDynLib* lib, char* outPath, int* inOutPathSize, BfpLibResult* outResult) -{ - Beefy::String path; - - - Dl_info info; - if (dladdr((void*)lib, &info) == 0) - { - OUTRESULT(BfpLibResult_UnknownError); - return; - } - - path = info.dli_fname; - TryStringOut(path, outPath, inOutPathSize, (BfpResult*)outResult); -} - -BFP_EXPORT void* BFP_CALLTYPE BfpDynLib_GetProcAddress(BfpDynLib* lib, const char* name) -{ - return dlsym((void*)lib, name); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Create(const char* path, BfpFileResult* outResult) -{ - if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) - { - switch (errno) - { - case EEXIST: - OUTRESULT(BfpFileResult_AlreadyExists); - break; - case ENOENT: - OUTRESULT(BfpFileResult_NotFound); - break; - default: - OUTRESULT(BfpFileResult_UnknownError); - break; - } - } - else - OUTRESULT(BfpFileResult_Ok); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Rename(const char* oldName, const char* newName, BfpFileResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Delete(const char* path, BfpFileResult* outResult) -{ - if (rmdir(path) != 0) - { - switch (errno) - { - case ENOENT: - OUTRESULT(BfpFileResult_NotFound); - break; - default: - OUTRESULT(BfpFileResult_UnknownError); - break; - } - } - else - OUTRESULT(BfpFileResult_Ok); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_GetCurrent(char* outPath, int* inOutPathSize, BfpFileResult* outResult) -{ - char* str = getcwd(NULL, 0); - Beefy::String path = str; - free(str); - TryStringOut(path, outPath, inOutPathSize, (BfpResult*)outResult); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_SetCurrent(const char* path, BfpFileResult* outResult) -{ - if (chdir(path) != 0) - OUTRESULT(BfpFileResult_NotFound); - else - OUTRESULT(BfpFileResult_Ok); -} - -BFP_EXPORT bool BFP_CALLTYPE BfpDirectory_Exists(const char* path) -{ - struct stat statbuf = {0}; - int result = stat(path, &statbuf); - if (result != 0) - return false; - return S_ISDIR(statbuf.st_mode); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_GetSysDirectory(BfpSysDirectoryKind sysDirKind, char* outPath, int* inOutPathLen, BfpFileResult* outResult) -{ - String path = "~"; - TryStringOut(path, outPath, inOutPathLen, (BfpResult*)outResult); -} - -BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_Create(const char* inName, BfpFileCreateKind createKind, BfpFileCreateFlags createFlags, BfpFileAttributes createdFileAttrs, BfpFileResult* outResult) -{ - auto _DoCreate = [&](String& name) - { - int flags = 0; - int mode = 0; - int pipePairHandle = -1; - - if ((createFlags & (BfpFileCreateFlag_Read | BfpFileCreateFlag_Write)) == (BfpFileCreateFlag_Read | BfpFileCreateFlag_Write)) - flags |= O_RDWR; - else if ((createFlags & BfpFileCreateFlag_Read) != 0) - flags |= O_RDONLY; - else if ((createFlags & BfpFileCreateFlag_Write) != 0) - flags |= O_WRONLY; - - if ((createFlags & BfpFileCreateFlag_Append) != 0) - flags |= O_APPEND; - if ((createFlags & BfpFileCreateFlag_Truncate) != 0) - flags |= O_TRUNC; - if ((createFlags & (BfpFileCreateFlag_NonBlocking | BfpFileCreateFlag_AllowTimeouts)) != 0) - flags |= O_NONBLOCK; - - if ((createFlags & BfpFileCreateFlag_Pipe) != 0) - { - name = "/tmp/" + name; - - if ((createKind == BfpFileCreateKind_CreateAlways) || - (createKind == BfpFileCreateKind_CreateIfNotExists)) - { - for (int pass = 0; pass < 2; pass++) - { - int result = mknod(name.c_str(), S_IFIFO | 0666, 0); - - if (result == 0) - break; - - int err = errno; - if (err == EEXIST) - { - err = remove(name.c_str()); - if (err == 0) - continue; - OUTRESULT(BfpFileResult_AlreadyExists); - return -1; - } - - OUTRESULT(BfpFileResult_UnknownError); - return -1; - } - } - } - else - { - if (createKind == BfpFileCreateKind_CreateAlways) - flags |= O_CREAT; - else if (createKind == BfpFileCreateKind_CreateIfNotExists) - flags |= O_CREAT | O_EXCL; - } - - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - - int result = open(name.c_str(), flags, mode); - //printf("BfpFile_Create %s %d %d %d\n", name.c_str(), result, flags, mode); - - if (result <= 0) - { - switch (errno) - { - case EEXIST: - OUTRESULT(BfpFileResult_AlreadyExists); - break; - case ENOENT: - OUTRESULT(BfpFileResult_NotFound); - break; - case EACCES: - OUTRESULT(BfpFileResult_AccessError); - break; - default: - OUTRESULT(BfpFileResult_UnknownError); - break; - } - return -1; - } - return result; - }; - - BfpFile* bfpFile = NULL; - - int result; - if ((createFlags & BfpFileCreateFlag_Pipe) != 0) - { - int readHandle; - int writeHandle; - - String name = inName; - String altName = name + "__"; - - bool isCreating = false; - if ((createKind == BfpFileCreateKind_CreateAlways) || - (createKind == BfpFileCreateKind_CreateIfNotExists)) - { - readHandle = _DoCreate(name); - writeHandle = _DoCreate(altName); - isCreating = true; - } - else - { - readHandle = _DoCreate(altName); - writeHandle = _DoCreate(name); - } - - if ((readHandle != -1) && (writeHandle != -1)) - { - OUTRESULT(BfpFileResult_Ok); - - BfpPipeInfo* pipeInfo = new BfpPipeInfo(); - pipeInfo->mWriteHandle = writeHandle; - if (isCreating) - pipeInfo->mPipePath = name; - bfpFile = new BfpFile(); - bfpFile->mHandle = readHandle; - bfpFile->mPipeInfo = pipeInfo; - } - else - { - if (readHandle != -1) - close(readHandle); - if (writeHandle != -1) - close(writeHandle); - - return NULL; - } - } - else - { - String name = inName; - int handle = _DoCreate(name); - if (handle == -1) - return NULL; - - OUTRESULT(BfpFileResult_Ok); - bfpFile = new BfpFile(); - bfpFile->mHandle = handle; - } - - OUTRESULT(BfpFileResult_Ok); - if ((createFlags & (BfpFileCreateFlag_NonBlocking | BfpFileCreateFlag_AllowTimeouts)) != 0) - bfpFile->mNonBlocking = true; - if ((createFlags & BfpFileCreateFlag_AllowTimeouts) != 0) - bfpFile->mAllowTimeout = true; - return bfpFile; -} - -BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult) -{ - int h = -1; - switch (kind) - { - case BfpFileStdKind_StdOut: - h = STDOUT_FILENO; - break; - case BfpFileStdKind_StdError: - h = STDERR_FILENO; - break; - case BfpFileStdKind_StdIn: - h = STDIN_FILENO; - break; - } - if (h == -1) - { - OUTRESULT(BfpFileResult_NotFound); - return NULL; - } - - BfpFile* bfpFile = new BfpFile(); - bfpFile->mHandle = h; - bfpFile->mIsStd = true; - - return bfpFile; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Release(BfpFile* file) -{ - if ((file->mHandle != -1) && (!file->mIsStd)) - close(file->mHandle); - if (file->mPipeInfo != NULL) - { - if (file->mPipeInfo->mWriteHandle != -1) - close(file->mPipeInfo->mWriteHandle); - - if (!file->mPipeInfo->mPipePath.IsEmpty()) - { - int worked = remove(file->mPipeInfo->mPipePath.c_str()); - remove((file->mPipeInfo->mPipePath + "__").c_str()); - //printf("Removing %s %d\n", file->mPipeInfo->mPipePath.c_str(), worked); - } - } - - delete file; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Close(BfpFile* file, BfpFileResult* outResult) -{ - if (file->mHandle != -1) - { - close(file->mHandle); - file->mHandle = -1; - if (file->mPipeInfo != NULL) - { - close(file->mPipeInfo->mWriteHandle); - file->mPipeInfo->mWriteHandle = -1; - } - - OUTRESULT(BfpFileResult_Ok); - } - else - OUTRESULT(BfpFileResult_UnknownError); -} - -BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Write(BfpFile* file, const void* buffer, intptr size, int timeoutMS, BfpFileResult* outResult) -{ - int writeHandle = file->mHandle; - if (file->mPipeInfo != NULL) - writeHandle = file->mPipeInfo->mWriteHandle; - - intptr writeCount = ::write(writeHandle, buffer, size); -// if ((writeCount > 0) && (file->mIsPipe)) -// { -// ::fsync(file->mHandle); -// } - - if (writeCount < 0) - OUTRESULT(BfpFileResult_UnknownError); - else if (writeCount != size) - OUTRESULT(BfpFileResult_PartialData); - else - OUTRESULT(BfpFileResult_Ok); - return writeCount; -} - -BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Read(BfpFile* file, void* buffer, intptr size, int timeoutMS, BfpFileResult* outResult) -{ - if (file->mNonBlocking) - { - if (!file->mAllowTimeout) - timeoutMS = -1; - - timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = timeoutMS * 1000; - - fd_set readFDSet; - FD_ZERO(&readFDSet); - FD_SET(file->mHandle, &readFDSet); - - fd_set errorFDSet; - FD_ZERO(&errorFDSet); - FD_SET(file->mHandle, &errorFDSet); - - if (select(file->mHandle + 1, &readFDSet, NULL, &errorFDSet, (timeoutMS == -1) ? NULL : &timeout) < 0) - { - OUTRESULT(BfpFileResult_Timeout); - return 0; - } - } - - intptr readCount = ::read(file->mHandle, buffer, size); - if (readCount < 0) - OUTRESULT(BfpFileResult_UnknownError); - else if (readCount != size) - OUTRESULT(BfpFileResult_PartialData); - else - OUTRESULT(BfpFileResult_Ok); - return readCount; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Flush(BfpFile* file) -{ - ::fsync(file->mHandle); -} - -BFP_EXPORT int64 BFP_CALLTYPE BfpFile_GetFileSize(BfpFile* file) -{ - int64 oldPos = (int64)lseek(file->mHandle, 0, SEEK_CUR); - int64 size = (int64)lseek(file->mHandle, 0, SEEK_END); - lseek(file->mHandle, oldPos, SEEK_SET); - return (intptr)size; -} - -BFP_EXPORT int64 BFP_CALLTYPE BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind) -{ - int whence; - if (seekKind == BfpFileSeekKind_Absolute) - whence = SEEK_SET; - else if (seekKind == BfpFileSeekKind_Relative) - whence = SEEK_CUR; - else - whence = SEEK_END; - return lseek(file->mHandle, offset, whence); -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Truncate(BfpFile* file) -{ - int64 curPos = (int64)lseek(file->mHandle, 0, SEEK_CUR); - if (ftruncate(file->mHandle, curPos) != 0) - { - //TODO: Report error? - } -} - -BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFile_GetTime_LastWrite(const char* path) -{ - struct stat statbuf = {0}; - int result = stat(path, &statbuf); - if (result != 0) - return 0; - return statbuf.st_mtime; -} - -BFP_EXPORT BfpFileAttributes BFP_CALLTYPE BfpFile_GetAttributes(const char* path, BfpFileResult* outResult) -{ - NOT_IMPL; - return (BfpFileAttributes)0; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_SetAttributes(const char* path, BfpFileAttributes attribs, BfpFileResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Copy(const char* oldPath, const char* newPath, BfpFileCopyKind copyKind, BfpFileResult* outResult) -{ - int fd_to, fd_from; - char buf[4096]; - ssize_t nread; - - fd_from = open(oldPath, O_RDONLY); - if (fd_from < 0) - { - OUTRESULT(BfpFileResult_NotFound); - return; - } - - int flags = O_WRONLY | O_CREAT; - if (copyKind == BfpFileCopyKind_IfNotExists) - flags |= O_EXCL; - - fd_to = open(newPath, flags, 0666); - if (fd_to < 0) - { - if (errno == EEXIST) - { - OUTRESULT(BfpFileResult_AlreadyExists); - goto out_error; - } - - OUTRESULT(BfpFileResult_UnknownError); - goto out_error; - } - - while (nread = read(fd_from, buf, sizeof buf), nread > 0) - { - char *out_ptr = buf; - ssize_t nwritten; - - do { - nwritten = write(fd_to, out_ptr, nread); - - if (nwritten >= 0) - { - nread -= nwritten; - out_ptr += nwritten; - } - else if (errno != EINTR) - { - OUTRESULT(BfpFileResult_UnknownError); - goto out_error; - } - } while (nread > 0); - } - - if (nread == 0) - { - if (close(fd_to) < 0) - { - fd_to = -1; - OUTRESULT(BfpFileResult_UnknownError); - goto out_error; - } - close(fd_from); - - /* Success! */ - OUTRESULT(BfpFileResult_Ok); - return; - } - -out_error: - close(fd_from); - if (fd_to >= 0) - close(fd_to); -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Rename(const char* oldPath, const char* newPath, BfpFileResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Delete(const char* path, BfpFileResult* outResult) -{ - if (remove(path) != 0) - { - switch (errno) - { - case ENOENT: - OUTRESULT(BfpFileResult_NotFound); - break; - default: - OUTRESULT(BfpFileResult_UnknownError); - break; - } - } - else - OUTRESULT(BfpFileResult_Ok); -} - -BFP_EXPORT bool BFP_CALLTYPE BfpFile_Exists(const char* path) -{ - struct stat statbuf = {0}; - int result = stat(path, &statbuf); - if (result != 0) - return false; - return !S_ISDIR(statbuf.st_mode); -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_GetTempPath(char* outPath, int* inOutPathSize, BfpFileResult* outResult) -{ - NOT_IMPL; -} - -static const char cHash64bToChar[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', - 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', - 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_' }; -static void HashEncode64(StringImpl& outStr, uint64 val) -{ - for (int i = 0; i < 10; i++) - { - int charIdx = (int)((val >> (i * 6)) & 0x3F) - 1; - if (charIdx != -1) - outStr.Append(cHash64bToChar[charIdx]); - } -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_GetTempFileName(char* outName, int* inOutNameSize, BfpFileResult* outResult) -{ - static uint32 uniqueIdx = 0; - BfpSystem_InterlockedExchangeAdd32(&uniqueIdx, 1); - - Beefy::HashContext ctx; - ctx.Mixin(uniqueIdx); - ctx.Mixin(getpid()); - ctx.Mixin(Beefy::BFGetTickCountMicro()); - - uint64 hash = ctx.Finish64(); - - String str = "/tmp/bftmp_"; - HashEncode64(str, hash); - - TryStringOut(str, outName, inOutNameSize, (BfpResult*)outResult); -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_GetFullPath(const char* inPath, char* outPath, int* inOutPathSize, BfpFileResult* outResult) -{ - String str; - - if (inPath[0] == '/') - { - str = inPath; - } - else - { - char* cwdPtr = getcwd(NULL, 0); - Beefy::String cwdPath = cwdPtr; - free(cwdPtr); - str = GetAbsPath(inPath, cwdPath); - } - TryStringOut(str, outPath, inOutPathSize, (BfpResult*)outResult); -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_GetActualPath(const char* inPath, char* outPath, int* inOutPathSize, BfpFileResult* outResult) -{ - NOT_IMPL; -} - -// BfpFindFileData - -struct BfpFindFileData -{ - BfpFindFileFlags mFlags; - DIR* mDirStruct; - Beefy::String mWildcard; - Beefy::String mDirPath; - - dirent* mDirEnt; - bool mHasStat; - struct stat mStat; -}; - -BFP_EXPORT BfpFindFileData* BFP_CALLTYPE BfpFindFileData_FindFirstFile(const char* path, BfpFindFileFlags flags, BfpFileResult* outResult) -{ - Beefy::String findStr = path; - Beefy::String wildcard; - - int lastSlashPos = std::max((int)findStr.LastIndexOf('/'), (int)findStr.LastIndexOf('\\')); - if (lastSlashPos != -1) - { - wildcard = findStr.Substring(lastSlashPos + 1); - findStr = findStr.Substring(0, lastSlashPos); - } - if (wildcard == "*.*") - wildcard = "*"; - - DIR* dir = opendir(findStr.c_str()); - if (dir == NULL) - { - OUTRESULT(BfpFileResult_NotFound); - return NULL; - } - - BfpFindFileData* findData = new BfpFindFileData(); - findData->mFlags = flags; - findData->mDirPath = findStr; - findData->mDirStruct = dir; - findData->mWildcard = wildcard; - findData->mHasStat = false; - findData->mDirEnt = NULL; - - if (!BfpFindFileData_FindNextFile(findData)) - { - OUTRESULT(BfpFileResult_NoResults); - delete findData; - return NULL; - } - - OUTRESULT(BfpFileResult_Ok); - return findData; -} - -static void GetStat(BfpFindFileData* findData) -{ - if (findData->mHasStat) - return; - - Beefy::String filePath = findData->mDirPath + "/" + findData->mDirEnt->d_name; - - findData->mStat = { 0 }; - int result = stat(filePath.c_str(), &findData->mStat); - - findData->mHasStat = true; -} - -static bool BfpFindFileData_CheckFilter(BfpFindFileData* findData) -{ - bool isDir = false; - if (findData->mDirEnt->d_type == DT_DIR) - isDir = true; - if (findData->mDirEnt->d_type == DT_LNK) - { - GetStat(findData); - isDir = S_ISDIR(findData->mStat.st_mode); - } - - if (isDir) - { - if ((findData->mFlags & BfpFindFileFlag_Directories) == 0) - return false; - - if ((strcmp(findData->mDirEnt->d_name, ".") == 0) || (strcmp(findData->mDirEnt->d_name, "..") == 0)) - return false; - } - else - { - if ((findData->mFlags & BfpFindFileFlag_Files) == 0) - return false; - } - - //TODO: Check actual wildcards. - - return true; -} - -BFP_EXPORT bool BFP_CALLTYPE BfpFindFileData_FindNextFile(BfpFindFileData* findData) -{ - while (true) - { - findData->mHasStat = false; - findData->mDirEnt = readdir(findData->mDirStruct); - if (findData->mDirEnt == NULL) - return false; - - if (BfpFindFileData_CheckFilter(findData)) - break; - } - - return true; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFindFileData_GetFileName(BfpFindFileData* findData, char* outName, int* inOutNameSize, BfpFileResult* outResult) -{ - Beefy::String name = findData->mDirEnt->d_name; - TryStringOut(name, outName, inOutNameSize, (BfpResult*)outResult); -} - -BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_LastWrite(BfpFindFileData* findData) -{ - GetStat(findData); - return BfpToTimeStamp(findData->mStat.st_mtimespec); -} - -BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_Created(BfpFindFileData* findData) -{ - GetStat(findData); - return BfpToTimeStamp(findData->mStat.st_ctimespec); -} - -BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_Access(BfpFindFileData* findData) -{ - GetStat(findData); - return BfpToTimeStamp(findData->mStat.st_atimespec); -} - -BFP_EXPORT BfpFileAttributes BFP_CALLTYPE BfpFindFileData_GetFileAttributes(BfpFindFileData* findData) -{ - BfpFileAttributes flags = BfpFileAttribute_None; - if (S_ISDIR(findData->mStat.st_mode)) - flags = (BfpFileAttributes)(flags | BfpFileAttribute_Directory); - if (S_ISREG(findData->mStat.st_mode)) - flags = (BfpFileAttributes)(flags | BfpFileAttribute_Normal); - else if (!S_ISLNK(findData->mStat.st_mode)) - flags = (BfpFileAttributes)(flags | BfpFileAttribute_Device); - if ((findData->mStat.st_mode & S_IRUSR) == 0) - flags = (BfpFileAttributes)(flags | BfpFileAttribute_ReadOnly); - return flags; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFindFileData_Release(BfpFindFileData* findData) -{ - delete findData; -} - -BFP_EXPORT int BFP_CALLTYPE BfpStack_CaptureBackTrace(int framesToSkip, intptr* outFrames, int wantFrameCount) -{ - // - return 0; -} - -BFP_EXPORT void BFP_CALLTYPE BfpOutput_DebugString(const char* str) -{ - fputs(str, stdout); - fflush(stdout); -} - -////////////////////////////////////////////////////////////////////////// - -void Beefy::BFFatalError(const StringImpl& message, const StringImpl& file, int line) -{ - String error; - error += "ERROR: "; - error += message; - error += " in "; - error += file; - error += StrFormat(" line %d", line); - BfpSystem_FatalError(error.c_str(), "FATAL ERROR"); -} - -#if 0 - -#include "Common.h" -#include "BFPlatform.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "SDL_timer.h" - -int gBFPlatformLastError = 0; - -#define NOT_IMPL throw "Unimplemented"; - -inline uint64 get_mach_frequency() -{ - uint64 freq = 0; - if (freq == 0) - { - static mach_timebase_info_data_t sTimebaseInfo; - if ( sTimebaseInfo.denom == 0) - (void) mach_timebase_info(&sTimebaseInfo); - - freq = (uint64_t)1000000 * (uint64)sTimebaseInfo.denom / (uint64)sTimebaseInfo.numer; - } - return freq; -} - -uint32 Beefy::BFTickCount() -{ - /*uint64 t; - t = mach_absolute_time(); - t /= get_mach_frequency(); - return (uint32)t;*/ - return SDL_GetTicks(); -} - -int64 Beefy::EndianSwap(int64 val) -{ - return CFSwapInt64(val); -} - -bool IsDebuggerPresent() -{ - /* int mib[4]; - struct kinfo_proc info; - size_t size; - - info.kp_proc.p_flag = 0; - mib[0] = CTL_KERN; - mib[1] = KERN_PROC; - mib[2] = KERN_PROC_PID; - mib[3] = getpid(); - - size = sizeof(info); - sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); - - return ((info.kp_proc.p_flag & P_TRACED) != 0);*/ - return true; -} - -void OutputDebugStringA(const char* str) -{ - if (IsDebuggerPresent()) - fputs(str, stdout); -} - -void OutputDebugStringW(const wchar_t* str) -{ - if (IsDebuggerPresent()) - { - fputws(str, stdout); - } -} - -void* BFTlsGetValue(BFTlsKey tlsKey) -{ - return pthread_getspecific(tlsKey); -} - -bool BFTlsSetValue(BFTlsKey tlsKey, void* tlsValue) -{ - return pthread_setspecific(tlsKey, tlsValue) == 0; -} - -BFTlsKey BFTlsAlloc() -{ - pthread_key_t key = NULL; - pthread_key_create(&key, NULL); - return key; -} - -bool BFTlsFree(BFTlsKey tlsKey) -{ - return pthread_key_delete(tlsKey) == 0; -} - -HANDLE GetModuleHandle(HANDLE h) -{ - NOT_IMPL - return 0; -} - -uint32 GetModuleFileNameW(uint32 hModule, wchar_t* lpFilename, uint32 length) -{ - return (uint32)mbstowcs(lpFilename, gBFArgV[0], length); -} - -uint32 GetModuleFileNameA(uint32 hModule, char* lpFilename, uint32 length) -{ - strncpy(lpFilename, gBFArgV[0], length); - return (uint32)strlen(lpFilename); -} - -HMODULE LoadLibraryA(const char* fileName) -{ - HMODULE mod = NULL; - /*(HMODULE)dlopen(fileName, RTLD_LAZY); - if (mod == NULL) - mod = (HMODULE)dlopen((std::string(fileName) + ".dylib").c_str(), RTLD_LAZY); - if (mod == NULL) - mod = (HMODULE)dlopen((std::string(fileName) + ".so").c_str(), RTLD_LAZY);*/ - - static const char* prefixes[] = {NULL, "lib"}; - static const char* suffixes[] = {NULL, ".so", ".dylib"}; - - for (int prefixIdx = 0; prefixIdx < sizeof(prefixes)/sizeof(prefixes[0]); prefixIdx++) - { - for (int suffixIdx = 0; suffixIdx < sizeof(suffixes)/sizeof(suffixes[0]); suffixIdx++) - { - const char* prefix = prefixes[prefixIdx]; - const char* suffix = suffixes[suffixIdx]; - - std::string checkName = fileName; - if (prefix != NULL) - checkName = std::string(prefix) + checkName; - if (suffix != NULL) - checkName += suffix; - - mod = (HMODULE)dlopen(checkName.c_str(), RTLD_LAZY); - if (mod != NULL) - return mod; - } - } - - return NULL; -} - -BFLibProcAddr GetProcAddress(HMODULE mod, const char* name) -{ - return (BFLibProcAddr)dlsym(mod, name); -} - -bool CreateDirectoryW(const wchar_t* str, void* securityAttributes) -{NOT_IMPL - return false; -} - -bool RemoveDirectoryW(const wchar_t* str) -{NOT_IMPL - return false; -} - -int GetLastError() -{ - return gBFPlatformLastError; -} - -void BFSetLastError(int error) -{ - gBFPlatformLastError = error; -} - -int* GetStdHandle(int32 handleId) -{ - if (handleId == STD_INPUT_HANDLE) - return (int*)STDIN_FILENO; - if (handleId == STD_OUTPUT_HANDLE) - return (int*)STDOUT_FILENO; - return (int*)STDERR_FILENO; -} - -#ifdef USING_PTHREAD -intptr GetCurrentThreadId() -{ - return (intptr)pthread_self(); -} - -HANDLE GetCurrentThread() -{ - return pthread_self(); -} - -bool SetThreadPriority(HANDLE hThread, int nPriority) -{ - return false; -} - -void* CreateThread(void* threadAttributes, int32 stackSize, BFThreadStartProc threadStartProc, void* param, uint32 flags, intptr* threadId) -{ - BF_ASSERT(sizeof(pthread_t) <= sizeof(void*)); - pthread_t thread; - pthread_attr_t params; - pthread_attr_init(¶ms); - pthread_attr_setstacksize(¶ms, stackSize); - //pthread_attr_setdetachstate(¶ms,PTHREAD_CREATE_DETACHED); - pthread_create(threadId, ¶ms, (void*(*)(void *))threadStartProc, param); - thread = (pthread_t)*threadId; - pthread_attr_destroy(¶ms); - - //printf("CreateThread: %08X\n", (intptr)thread); - - return (void*)thread; -} - -void ResumeThread(HANDLE thread) -{NOT_IMPL - thread_suspend(thread); -} - -uint32 SuspendThread(HANDLE thread) -{NOT_IMPL -} -#else -BF_THREADID GetCurrentThreadId() -{ - return pthread_self(); -} - -HANDLE GetCurrentThread() -{ - return (HANDLE)(intptr)mach_thread_self(); -} - -static int gThreadPriorityDefaultValue = -1; - -int GetThreadPriority(HANDLE hThread) -{ - mach_msg_type_number_t count = 1; - boolean_t getDefault = false; - thread_precedence_policy_data_t precedence; - precedence.importance = -1; - kern_return_t result = thread_policy_get((thread_act_t)(intptr)hThread, - THREAD_PRECEDENCE_POLICY, - (thread_policy_t)&precedence, - &count, - &getDefault); - return precedence.importance - gThreadPriorityDefaultValue; -} - -bool SetThreadPriority(HANDLE hThread, int nPriority) -{ - /*thread_precedence_policy_data_t precedence; - precedence.importance = 0; - - if (gThreadPriorityDefaultValue == -1) - { - mach_msg_type_number_t count = 1; - boolean_t getDefault = false; - kern_return_t result = thread_policy_get((thread_act_t)(intptr)hThread, - THREAD_PRECEDENCE_POLICY, - (thread_policy_t)&precedence, - &count, - &getDefault); - gThreadPriorityDefaultValue = precedence.importance; - } - precedence.importance = gThreadPriorityDefaultValue + nPriority * 16; - kern_return_t result = thread_policy_set((thread_act_t)(intptr)hThread, - THREAD_PRECEDENCE_POLICY, - (thread_policy_t)&precedence, - THREAD_PRECEDENCE_POLICY_COUNT); - return result == 0;*/ - - int policy = 0; - struct sched_param sched; - sched.sched_priority = 0; - pthread_getschedparam(pthread_self(), &policy, &sched); - sched.sched_priority = std::min(nPriority * 16 + 47, 62); - //int retVal = pthread_setschedparam(pthread_self(), policy, &sched); - - return true; -} - -HANDLE OpenThread(int desiredAccess, bool inheritHandle, BF_THREADID threadId) -{ - return (HANDLE)(intptr)mach_thread_self(); -} - -void* CreateThread(void* threadAttributes, int32 stackSize, BFThreadStartProc threadStartProc, void* param, uint32 flags, BF_THREADID* threadId) -{ - BF_ASSERT(sizeof(pthread_t) <= sizeof(void*)); - pthread_t thread; - pthread_attr_t params; - pthread_attr_init(¶ms); - pthread_attr_setstacksize(¶ms, stackSize); - //pthread_attr_setdetachstate(¶ms,PTHREAD_CREATE_DETACHED); - pthread_create(&thread, ¶ms, (void*(*)(void *))threadStartProc, param); - pthread_attr_destroy(¶ms); - *threadId = thread; - - //printf("CreateThread: %08X\n", (int32)(intptr)thread); - - return (void*)thread; -} - -uint32 SuspendThread(HANDLE thread) -{ - kern_return_t kernResult = thread_suspend((thread_act_t)(intptr)thread); - BF_ASSERT(kernResult == KERN_SUCCESS); - return 0; -} - -uint32 ResumeThread(HANDLE thread) -{ - kern_return_t kernResult = thread_resume((thread_act_t)(intptr)thread); - BF_ASSERT(kernResult == KERN_SUCCESS); - return 0; -} - - -#endif - -void Sleep(int32 ms) -{ - usleep(ms * 1000); -} - -struct BFFindFileData -{ - DIR* mDirStruct; - std::string mWildcard; -}; - -HANDLE FindFirstFileW(wchar_t* lpFileName, WIN32_FIND_DATAW* lpFindFileData) -{ - std::string findStr = Beefy::UTF8Encode(lpFileName); - std::string wildcard; - - int lastSlashPos = std::max((int)findStr.rfind('/'), (int)findStr.rfind('\\')); - if (lastSlashPos != -1) - { - wildcard = findStr.substr(lastSlashPos + 1); - findStr = findStr.substr(0, lastSlashPos); - } - - DIR* dir = opendir(findStr.c_str()); - if (dir == NULL) - { - BFSetLastError(ERROR_FILE_NOT_FOUND); - return INVALID_HANDLE_VALUE; - } - - BFFindFileData* bfFindFileData = new BFFindFileData(); - bfFindFileData->mDirStruct = dir; - bfFindFileData->mWildcard = wildcard; - - if (!FindNextFileW((HANDLE)bfFindFileData, lpFindFileData)) - { - FindClose((HANDLE)bfFindFileData); - BFSetLastError(ERROR_NO_MORE_FILES); - return INVALID_HANDLE_VALUE; - } - - return (HANDLE)bfFindFileData; -} - -void BFSystemTimeToFileTime(time_t timeT, long nsec, FILETIME* lpFileTime) -{ - uint64 ft64 = (timeT * 10000000ULL) + (nsec / 100); - lpFileTime->dwHighDateTime = (uint32)(ft64 >> 32); - lpFileTime->dwLowDateTime = (uint32)ft64; -} - -void BFSystemTimeToFileTime(timespec& timeSpec, FILETIME* lpFileTime) -{ - uint64 ft64 = (timeSpec.tv_nsec * 10000000ULL) + (timeSpec.tv_nsec / 100); - lpFileTime->dwHighDateTime = (uint32)(ft64 >> 32); - lpFileTime->dwLowDateTime = (uint32)ft64; -} - -bool FindNextFileW(HANDLE hFindFile, WIN32_FIND_DATAW* lpFindFileData) -{ - memset(lpFindFileData, 0, sizeof(WIN32_FIND_DATAW)); - - BFFindFileData* bfFindFileData = (BFFindFileData*)hFindFile; - dirent* ent = NULL; - while (true) - { - ent = readdir(bfFindFileData->mDirStruct); - if (ent == NULL) - return false; - - if (bfFindFileData->mWildcard == "*") - break; - std::string fileName = ent->d_name; - if (bfFindFileData->mWildcard[0] == '*') - { - if (fileName.length() < bfFindFileData->mWildcard.length() - 1) - continue; - - std::string checkFileName = fileName.substr(fileName.length() - bfFindFileData->mWildcard.length() + 1); - if (checkFileName == bfFindFileData->mWildcard.substr(1)) - break; - } - } - mbstowcs(lpFindFileData->cFileName, ent->d_name, 1024); - - struct stat statbuf = {0}; - int result = stat(ent->d_name, &statbuf); - if (result == -1) - return -1; - if (S_ISDIR(statbuf.st_mode)) - lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; - if (S_ISREG(statbuf.st_mode)) - lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_NORMAL; - else if (!S_ISLNK(statbuf.st_mode)) - lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_DEVICE; - if ((statbuf.st_mode & S_IRUSR) == 0) - lpFindFileData->dwFileAttributes |= FILE_ATTRIBUTE_READONLY; - - lpFindFileData->nFileSizeLow = (int32)statbuf.st_size; - lpFindFileData->nFileSizeHigh = (int32)(statbuf.st_size >> 32); - BFSystemTimeToFileTime(statbuf.st_ctimespec, &lpFindFileData->ftCreationTime); - BFSystemTimeToFileTime(statbuf.st_atimespec, &lpFindFileData->ftLastAccessTime); - BFSystemTimeToFileTime(statbuf.st_mtimespec, &lpFindFileData->ftLastWriteTime); - - return true; -} - -bool FindClose(HANDLE hFindFile) -{ - BFFindFileData* bfFindFileData = (BFFindFileData*)hFindFile; - closedir(bfFindFileData->mDirStruct); - delete bfFindFileData; - return true; -} - -uint32 GetCurrentDirectoryW(uint32 nBufferLength, wchar_t* lpBuffer) -{ - char str[2048]; - getcwd(str, 2048); - return (uint32)mbstowcs(lpBuffer, str, nBufferLength); -} - -bool SetCurrentDirectoryW(wchar_t* lpBuffer) -{ - if (chdir(Beefy::UTF8Encode(lpBuffer).c_str()) == 0) - return true; - BFSetLastError(ERROR_FILE_NOT_FOUND); - return false; -} - -bool CopyFileW(wchar_t* lpExistingFileName, wchar_t* lpNewFileName, bool allowOverwrite) -{NOT_IMPL - return true; -} - -bool MoveFileW(wchar_t* lpExistingFileName, wchar_t* lpNewFileName) -{NOT_IMPL - return true; -} - -bool DeleteFileW(wchar_t* lpFileName) -{NOT_IMPL - return true; -} - -bool ReplaceFileW(wchar_t* lpReplacedFileName, wchar_t* lpReplacementFileName, wchar_t* lpBackupFileName, - uint32 dwReplaceFlags, void* lpExclude, void* lpReserved) -{NOT_IMPL - return true; -} - -bool SetFileAttributesW(wchar_t* lpFileName, uint32 dwFileAttributes) -{NOT_IMPL - return true; -} - -int32 GetFileType(HANDLE fileHandle) -{ - if (isatty((int)(intptr)fileHandle)) - return FILE_TYPE_CHAR; - return FILE_TYPE_DISK; -} - -bool GetFileAttributesExW(wchar_t* lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, void* lpFileInformation) -{NOT_IMPL - return 0; -} - -HANDLE CreateFileW(wchar_t* lpFileName, uint32 dwDesiredAccess, uint32 dwShareMode, SECURITY_ATTRIBUTES* lpSecurityAttributes, - uint32 dwCreationDisposition, uint32 dwFlagsAndAttributes, HANDLE hTemplateFile) -{ - std::string fileName = Beefy::UTF8Encode(lpFileName); - int flags = 0; - int mode = 0; - - if ((dwDesiredAccess & (GENERIC_READ | GENERIC_WRITE)) == (GENERIC_READ | GENERIC_WRITE)) - flags |= O_RDWR; - else if (dwDesiredAccess & GENERIC_READ) - flags |= O_RDONLY; - else if (dwDesiredAccess & GENERIC_WRITE) - flags |= O_WRONLY; - - if (dwCreationDisposition == OPEN_ALWAYS) - flags |= O_CREAT; - else if (dwCreationDisposition == CREATE_ALWAYS) - flags |= O_CREAT | O_TRUNC; - else if (dwCreationDisposition == CREATE_NEW) - flags |= O_CREAT | O_EXCL; - else if (dwCreationDisposition == TRUNCATE_EXISTING) - flags |= O_TRUNC; - - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - - return (HANDLE)(intptr)open(fileName.c_str(), flags, mode); -} - -bool CreatePipe(HANDLE* hReadPipe, HANDLE* hWritePipe, SECURITY_ATTRIBUTES* lpPipeAttributes, uint32 nSize) -{NOT_IMPL - return true; -} - -bool WriteFile(HANDLE hFile, void* lpBuffer, uint32 nNumberOfBytesToWrite, uint32* lpNumberOfBytesWritten, OVERLAPPED* lpOverlapped) -{ -#ifdef BF_PLATFORM_IOS - int logType = -1; - if (hFile == (int*)STDOUT_FILENO) - logType = LOG_WARNING; - else if (hFile == (int*)STDERR_FILENO) - logType = LOG_ERR; - - if (logType != -1) - { - static std::string strOut; - strOut.resize(nNumberOfBytesToWrite); - memcpy(&strOut[0], lpBuffer, nNumberOfBytesToWrite); - if ((strOut[0] != '\r') && (strOut[0] != '\n')) - syslog(LOG_WARNING, "%s", strOut.c_str()); - } -#endif - - int writeCount = (int)::write((int)(intptr)hFile, lpBuffer, nNumberOfBytesToWrite); - if (writeCount == -1) - { - //TODO: set gBFPlatformLastError - lpNumberOfBytesWritten = 0; - return false; - } - - *lpNumberOfBytesWritten = (uint32)writeCount; - return true; -} - -static bool doSleep = false; - -bool ReadFile(HANDLE hFile, void* lpBuffer, uint32 nNumberOfBytesToRead, uint32* lpNumberOfBytesRead, OVERLAPPED* lpOverlapped) -{ - int readCount = (int)::read((int)(intptr)hFile, lpBuffer, nNumberOfBytesToRead); - - if (doSleep) - Sleep(1000); - - if (readCount == -1) - { - //TODO: set gBFPlatformLastError - lpNumberOfBytesRead = 0; - return false; - } - - *lpNumberOfBytesRead = (uint32)readCount; - return true; -} - -bool CloseHandle_File(HANDLE handle) -{ - return close((int)(intptr)handle) == 0; -} - -bool FlushFileBuffers(HANDLE handle) -{ - return fsync((int)(intptr)handle) == 0; -} - -int32 SetFilePointer(HANDLE handle, int32 distanceToMove, int32* distanceToMoveHigh, uint32 moveMethod) -{ - return (int32)lseek((int)(intptr)handle, distanceToMove, (moveMethod == FILE_BEGIN) ? SEEK_SET : (moveMethod == FILE_CURRENT) ? SEEK_CUR : SEEK_END); -} - -int32 GetFileSize(HANDLE hFile, uint32* fileSizeHigh) -{ - *fileSizeHigh = 0; - int32 oldPos = (int32)lseek((int)(intptr)hFile, 0, SEEK_CUR); - int32 size = (int32)lseek((int)(intptr)hFile, 0, SEEK_END); - lseek((int)(intptr)hFile, oldPos, SEEK_SET); - return size; -} - -bool SetEndOfFile(HANDLE hFile) -{ - int32 curPos = (int32)lseek((int)(intptr)hFile, 0, SEEK_CUR); - ftruncate((int)(intptr)hFile, curPos); - return true; -} - -bool SetFileTime(HANDLE hFile, const FILETIME* lpCreationTime, const FILETIME* lpLastAccessTime, const FILETIME* lpLastWriteTime) -{NOT_IMPL - return true; -} - -bool LockFile(HANDLE hFile, uint32 dwFileOffsetLow, uint32 dwFileOffsetHigh, uint32 nNumberOfBytesToLockLow, uint32 nNumberOfBytesToLockHigh) -{NOT_IMPL - return true; -} - -bool UnlockFile(HANDLE hFile, uint32 dwFileOffsetLow, uint32 dwFileOffsetHigh, uint32 nNumberOfBytesToUnlockLow, uint32 nNumberOfBytesToUnlockHigh) -{NOT_IMPL - return true; -} - -bool DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle, HANDLE* lpTargetHandle, - uint32 dwDesiredAccess, bool bInheritHandle, uint32 dwOptions) -{NOT_IMPL - return true; -} - -int32 GetTempPath(int32 bufferLen, wchar_t* str) -{NOT_IMPL - return 0; -} - -HANDLE CreateEventW(SECURITY_ATTRIBUTES* lpEventAttributes, bool bManualReset, bool bInitialState, wchar_t* lpName) -{ - BF_ASSERT(lpName == NULL); - Beefy::SyncEvent* syncEvent = new Beefy::SyncEvent(bManualReset, bInitialState); - return syncEvent; -} - -HANDLE OpenEventW(uint32 dwDesiredAccess, bool bInheritHandle, wchar_t* lpName) -{NOT_IMPL - return 0; -} - -bool SetEvent(HANDLE handle) -{ - ((Beefy::SyncEvent*)handle)->Set(); - return true; -} - -bool ResetEvent(HANDLE handle) -{ - ((Beefy::SyncEvent*)handle)->Reset(); - return true; -} - -bool CloseHandle_Event(HANDLE handle) -{ - delete (Beefy::SyncEvent*)handle; - return true; -} - - -int WaitForSingleObject(HANDLE obj, int waitMs) -{ - Beefy::SyncEvent* syncEvent = (Beefy::SyncEvent*)obj; - bool worked = syncEvent->WaitFor(waitMs); - return worked ? WAIT_OBJECT_0 : -1; -} - -int WaitForSingleObject_Thread(HANDLE obj, int waitMs) -{ - BF_ASSERT(waitMs == -1); - //printf("WaitForSingleObject_Thread: %08X\n", (int32)(intptr)obj); - int result = pthread_join((pthread_t)obj, NULL); - BF_ASSERT(result == 0); - return WAIT_OBJECT_0; -} - -HANDLE CreateMutexW(SECURITY_ATTRIBUTES* lpMutexAttributes, bool bInitialOwner, wchar_t* lpName) -{NOT_IMPL - return 0; -} - -HANDLE OpenMutexW(uint32 dwDesiredAccess, bool bInheritHandle, wchar_t* lpName) -{NOT_IMPL - return 0; -} - -bool ReleaseMutex(HANDLE mutex) -{NOT_IMPL - return true; -} - -uint32 FormatMessageW(uint32 dwFlags, void* lpSource, uint32 dwMessageId, uint32 dwLanguageId, wchar_t* lpBuffer, uint32 nSize, va_list* Arguments) -{NOT_IMPL - return 0; -} - -int32 WSAGetLastError() -{NOT_IMPL - return 0; -} - -void GetExitCodeProcess(HANDLE handle, DWORD* code) -{NOT_IMPL -} - -bool CloseHandle_Thread(HANDLE handle) -{NOT_IMPL - return true; -} - -bool CloseHandle_Process(HANDLE handle) -{NOT_IMPL - return true; -} - -bool GetProcessTimes(HANDLE handle, FILETIME* createTime, FILETIME* exitTime, FILETIME* kernelTime, FILETIME* userTime) -{NOT_IMPL - return true; -} - -bool GetProcessWorkingSetSize(HANDLE handle, size_t* curMin, size_t* curMax) -{NOT_IMPL - return true; -} - -bool SetProcessWorkingSetSize(HANDLE handle, size_t curMin, size_t curMax) -{NOT_IMPL - return true; -} - -bool EnumProcessModules(HANDLE handle, HMODULE* mods, DWORD cb, DWORD* needed) -{NOT_IMPL - return true; -} - -HANDLE OpenProcess(DWORD desiredAccess, bool inheritHandle, DWORD pid) -{NOT_IMPL - return 0; -} - -bool GetModuleBaseNameW(HANDLE handle, HMODULE mod, wchar_t* modname, int maxLen) -{NOT_IMPL - return true; -} - -bool GetModuleFileNameExW(HANDLE handle, HMODULE mod, wchar_t* modname, int maxLen) -{NOT_IMPL - return true; -} - -bool GetModuleInformation(HANDLE handle, HMODULE mod, MODULEINFO* modinfo, int modInfoSize) -{NOT_IMPL - return true; -} - -int GetPriorityClass(HANDLE handle) -{NOT_IMPL - return 0; -} - -bool SetPriorityClass(HANDLE handle, int priClass) -{NOT_IMPL - return true; -} - -bool TerminateProcess(HANDLE handle, int termCode) -{NOT_IMPL - return true; -} - -bool WaitForInputIdle(HANDLE handle, int ms) -{NOT_IMPL - return true; -} - -int32 GetCurrentProcessId() -{NOT_IMPL - return 0; -} - -HANDLE GetCurrentProcess() -{NOT_IMPL - return 0; -} - -bool GetDiskFreeSpaceExW(wchar_t* pathNameStr, ULARGE_INTEGER* wapi_free_bytes_avail, ULARGE_INTEGER*wapi_total_number_of_bytes, ULARGE_INTEGER* wapi_total_number_of_free_bytes) -{NOT_IMPL - return true; -} - -uint32 GetDriveTypeW(wchar_t* driveName) -{NOT_IMPL - return 0; -} - -bool GetVolumeInformationW(wchar_t* lpRootPathName, wchar_t* lpVolumeNameBuffer, uint32 nVolumeNameSize, uint32* lpVolumeSerialNumber, uint32* lpMaximumComponentLength, uint32* lpFileSystemFlags, wchar_t* lpFileSystemNameBuffer, uint32 nFileSystemNameSize) -{NOT_IMPL - return true; -} - -uint64 BFClockGetTime() -{ - static bool initialized = false; - static clock_serv_t cclock; - if (!initialized) - { - host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock); - initialized = true; - } - - time_t rawtime; - struct tm timeinfo; - time(&rawtime); - timeinfo = *localtime(&rawtime); - - mach_timespec_t mts; - clock_get_time(cclock, &mts); - //mach_port_deallocate(mach_task_self(), cclock); - //if (timeinfo.tm_isdst) - //mts.tv_sec += 60 * 60; - return ((mts.tv_sec /*+ timeinfo.tm_gmtoff*/) * 10000000ULL) + (mts.tv_nsec / 100); -} - -DWORD GetTimeZoneInformation(TIME_ZONE_INFORMATION* lpTimeZoneInformation) -{ - std::wstring tzName0 = Beefy::UTF8Decode(tzname[0]); - std::wstring tzName1 = Beefy::UTF8Decode(tzname[1]); - - bool isDST = false; - - time_t timeNow; - time(&timeNow); - tm tmNow = *gmtime(&timeNow); - isDST = tmNow.tm_isdst; - - struct tm checkTM; - memset(&checkTM, 0, sizeof(tm)); - checkTM.tm_mday = 1; - checkTM.tm_year = tmNow.tm_year; - time_t checkTime = mktime(&checkTM); - - time_t lastOffset = 0; - time_t minOffset = 0; - time_t maxOffset = 0; - - for (int pass = 0; pass < 2; pass++) - { - int searchDir = 60*60*24; - int thresholdCount = 0; - - while (true) - { - checkTime += searchDir; - - tm checkTM = *gmtime(&checkTime); - - if (checkTM.tm_year != tmNow.tm_year) - break; // No DST - - mktime(&checkTM); - - time_t offset = checkTM.tm_gmtoff; - if (lastOffset != offset) - { - if (thresholdCount == 0) - { - minOffset = offset; - maxOffset = offset; - } - else if (thresholdCount == 3) - { - SYSTEMTIME* sysTimeP = (offset == minOffset) ? - &lpTimeZoneInformation->StandardDate : - &lpTimeZoneInformation->DaylightDate; - - if (offset == minOffset) - tzName0 = Beefy::UTF8Decode(checkTM.tm_zone); - else - tzName1 = Beefy::UTF8Decode(checkTM.tm_zone); - - sysTimeP->wDay = 0; - sysTimeP->wDayOfWeek = 0; - sysTimeP->wYear = checkTM.tm_year + 1900; - sysTimeP->wMonth = checkTM.tm_mon; - sysTimeP->wDay = checkTM.tm_mday + 1; - sysTimeP->wHour = checkTM.tm_hour; - sysTimeP->wMinute = checkTM.tm_min; - sysTimeP->wSecond = checkTM.tm_sec; - sysTimeP->wMilliseconds = 0; - - break; - } - else - { - if (thresholdCount == 1) - searchDir /= -24; - else - searchDir /= -60; - minOffset = std::min(minOffset, offset); - maxOffset = std::max(maxOffset, offset); - } - thresholdCount++; - lastOffset = offset; - } - } - } - - wcsncpy(lpTimeZoneInformation->StandardName, tzName0.c_str(), 32); - wcsncpy(lpTimeZoneInformation->DaylightName, tzName1.c_str(), 32); - - lpTimeZoneInformation->DaylightBias = (int32)maxOffset; - lpTimeZoneInformation->StandardBias = (int32)minOffset; - - if (minOffset == maxOffset) - return 0; - return isDST ? 2 : 1; -} - -bool SystemTimeToFileTime(const SYSTEMTIME* lpSystemTime, FILETIME* lpFileTime) -{ - tm checkTM; - checkTM.tm_year = lpSystemTime->wYear - 1900; - checkTM.tm_mon = lpSystemTime->wMonth; - checkTM.tm_mday = lpSystemTime->wDay - 1; - checkTM.tm_hour = lpSystemTime->wHour; - checkTM.tm_min = lpSystemTime->wMinute; - checkTM.tm_sec = lpSystemTime->wSecond; - - time_t timeT = mktime(&checkTM); - - uint64 ft64 = timeT * 10000000ULL; - - lpFileTime->dwHighDateTime = (uint32)(ft64 >> 32); - lpFileTime->dwLowDateTime = (uint32)ft64; - return true; -} - -uint64 Beefy::BFGetTickCountMicro() -{ - static bool initialized = false; - static clock_serv_t cclock; - if (!initialized) - { - host_get_clock_service(mach_host_self(), REALTIME_CLOCK, &cclock); - initialized = true; - } - - mach_timespec_t mts; - clock_get_time(cclock, &mts); - return (mts.tv_sec * 1000000ULL) + (mts.tv_nsec / 1000); -} - -uint64 Beefy::BFGetTickCountMicroFast() -{ - return BFGetTickCountMicro(); -} - -#if (defined __IPHONEOS__) && !TARGET_IPHONE_SIMULATOR - -void BFGetThreadRegisters(HANDLE threadHandle, intptr* stackPtr, intptr* dataPtr) -{ - mach_msg_type_number_t thread_state_count = ARM_UNIFIED_THREAD_STATE_COUNT; - arm_unified_thread_state_t unifiedState; - kern_return_t kernResult = thread_get_state((thread_act_t)(intptr)threadHandle, ARM_UNIFIED_THREAD_STATE, (natural_t*)&unifiedState.ts_32, &thread_state_count); - -#ifdef BF32 - arm_thread_state32_t state = unifiedState.ts_32; -#else - zzz SHOULDN'T GET HERE - arm_thread_state64_t state = unifiedState.ts_64; -#endif - - BF_ASSERT(kernResult == KERN_SUCCESS); - - *stackPtr = (intptr)state.__sp; - - if (dataPtr != NULL) - { -#ifdef BF32 - intptr* curPtr = dataPtr; - *(curPtr++) = (intptr)state.__r[0]; - *(curPtr++) = (intptr)state.__r[1]; - *(curPtr++) = (intptr)state.__r[2]; - *(curPtr++) = (intptr)state.__r[3]; - *(curPtr++) = (intptr)state.__r[4]; - *(curPtr++) = (intptr)state.__r[5]; - *(curPtr++) = (intptr)state.__r[6]; - *(curPtr++) = (intptr)state.__r[7]; - *(curPtr++) = (intptr)state.__r[8]; - *(curPtr++) = (intptr)state.__r[9]; - *(curPtr++) = (intptr)state.__r[10]; - *(curPtr++) = (intptr)state.__r[11]; - *(curPtr++) = (intptr)state.__r[12]; - *(curPtr++) = (intptr)state.__lr; - *(curPtr++) = (intptr)state.__cpsr; -#else - intptr* curPtr = dataPtr; -#endif - int count = (int)(curPtr - dataPtr); - BF_ASSERT(count == BF_REGISTER_COUNT); - } -} - -#else - -void BFGetThreadRegisters(HANDLE threadHandle, intptr* stackPtr, intptr* dataPtr) -{ -#ifdef BF32 - mach_msg_type_number_t thread_state_count = x86_THREAD_STATE32_COUNT; - x86_thread_state32_t state; - kern_return_t kernResult = thread_get_state((thread_act_t)threadHandle, x86_THREAD_STATE32, (natural_t*)&state, &thread_state_count); -#else - mach_msg_type_number_t thread_state_count = x86_THREAD_STATE64_COUNT; - x86_thread_state64_t state; - kern_return_t kernResult = thread_get_state((thread_act_t)threadHandle, x86_THREAD_STATE64, (natural_t*)&state, &thread_state_count); -#endif - BF_ASSERT(kernResult == KERN_SUCCESS); - - *stackPtr = (intptr)state.__esp; - - if (dataPtr != NULL) - { -#ifdef BF32 - intptr* curPtr = dataPtr; - *(curPtr++) = (intptr)state.__eax; - *(curPtr++) = (intptr)state.__ebx; - *(curPtr++) = (intptr)state.__ecx; - *(curPtr++) = (intptr)state.__edx; - *(curPtr++) = (intptr)state.__esi; - *(curPtr++) = (intptr)state.__edi; - *(curPtr++) = (intptr)state.__ebp; -#else - intptr* curPtr = dataPtr; - *(curPtr++) = (intptr)ctx.Rax; - *(curPtr++) = (intptr)ctx.Rbx; - *(curPtr++) = (intptr)ctx.Rcx; - *(curPtr++) = (intptr)ctx.Rdx; - *(curPtr++) = (intptr)ctx.Rsi; - *(curPtr++) = (intptr)ctx.Rdi; - *(curPtr++) = (intptr)ctx.Rbp; - *(curPtr++) = (intptr)ctx.R8; - *(curPtr++) = (intptr)ctx.R9; - *(curPtr++) = (intptr)ctx.R10; - *(curPtr++) = (intptr)ctx.R11; - *(curPtr++) = (intptr)ctx.R12; - *(curPtr++) = (intptr)ctx.R13; - *(curPtr++) = (intptr)ctx.R14; - *(curPtr++) = (intptr)ctx.R15; -#endif - int count = curPtr - dataPtr; - BF_ASSERT(count == BF_REGISTER_COUNT); - } -} - -#endif - -int64 abs(int64 val) -{ - return llabs(val); -} - -void mkdir(const char* path) -{ - mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); -} +#define lseek64 lseek +#define ftruncate64 ftruncate -#endif \ No newline at end of file +#include "../posix/PosixCommon.cpp" \ No newline at end of file diff --git a/BeefySysLib/platform/ios/BFPlatform.h b/BeefySysLib/platform/ios/BFPlatform.h index 5f70b1b95..4987ca3d4 100644 --- a/BeefySysLib/platform/ios/BFPlatform.h +++ b/BeefySysLib/platform/ios/BFPlatform.h @@ -10,6 +10,7 @@ #endif #define BF_PLATFORM_IOS +#define BF_PLATFORM_POSIX #define BF_PLATFORM_OPENGL_ES2 #define BF_PLATFORM_FULLSCREEN diff --git a/BeefySysLib/platform/linux/LinuxCommon.cpp b/BeefySysLib/platform/linux/LinuxCommon.cpp index f21ddb07d..1a0d5cab5 100644 --- a/BeefySysLib/platform/linux/LinuxCommon.cpp +++ b/BeefySysLib/platform/linux/LinuxCommon.cpp @@ -1,2208 +1,6 @@ -#include "Common.h" -#include "BFPlatform.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../PlatformInterface.h" -#include "../PlatformHelper.h" -#include "../util/CritSect.h" -#include "../util/Dictionary.h" -#include "../util/Hash.h" -#include "backtrace.h" -#include "backtrace-supported.h" -#include "../third_party/stb/stb_sprintf.h" -#include -#include +#define BFP_HAS_BACKTRACE +#define BFP_HAS_EXECINFO +#define BFP_HAS_PTHREAD_TIMEDJOIN_NP +#define BFP_HAS_PTHREAD_GETATTR_NP -USING_NS_BF; - -struct BfpPipeInfo -{ - String mPipePath; - int mWriteHandle; -}; - -struct BfpFile -{ - BfpPipeInfo* mPipeInfo; - int mHandle; - bool mNonBlocking; - bool mAllowTimeout; - bool mIsStd; - - BfpFile() - { - mPipeInfo = NULL; - mHandle = -1; - mNonBlocking = false; - mAllowTimeout = false; - mIsStd = false; - } - - BfpFile(int handle) - { - mPipeInfo = NULL; - mHandle = handle; - mNonBlocking = false; - mAllowTimeout = false; - mIsStd = false; - } - - ~BfpFile() - { - delete mPipeInfo; - } -}; - -BfpTimeStamp BfpToTimeStamp(const timespec& ts) -{ - return (int64)(ts.tv_sec * 10000000) + (int64)(ts.tv_nsec / 100) + 116444736000000000; -} - -int gBFPlatformLastError = 0; - -uint32 Beefy::BFTickCount() -{ - struct timespec now; - if (clock_gettime(CLOCK_MONOTONIC, &now)) - return 0; - return (uint32)((uint64)now.tv_sec * 1000.0 + (uint64)now.tv_nsec / 1000000); -} - -int64 Beefy::EndianSwap(int64 val) -{ - return __builtin_bswap64(val); -} - -/*int* GetStdHandle(int32 handleId) -{ - if (handleId == STD_INPUT_HANDLE) - return (int*)STDIN_FILENO; - if (handleId == STD_OUTPUT_HANDLE) - return (int*)STDOUT_FILENO; - return (int*)STDERR_FILENO; -}*/ - -/*int32 GetFileType(HANDLE fileHandle) -{ - if (isatty(file->mHandleHandle)) - return FILE_TYPE_CHAR; - return FILE_TYPE_DISK; -}*/ - -/*bool WriteFile(HANDLE hFile, void* lpBuffer, uint32 nNumberOfBytesToWrite, uint32* lpNumberOfBytesWritten, OVERLAPPED* lpOverlapped) -{ -#ifdef BF_PLATFORM_IOS - int logType = -1; - if (hFile == (int*)STDOUT_FILENO) - logType = LOG_WARNING; - else if (hFile == (int*)STDERR_FILENO) - logType = LOG_ERR; - - if (logType != -1) - { - static std::string strOut; - strOut.resize(nNumberOfBytesToWrite); - memcpy(&strOut[0], lpBuffer, nNumberOfBytesToWrite); - if ((strOut[0] != '\r') && (strOut[0] != '\n')) - syslog(LOG_WARNING, "%s", strOut.c_str()); - } -#endif - - int writeCount = (int)::write((int)(intptr)hFile, lpBuffer, nNumberOfBytesToWrite); - if (writeCount == -1) - { - //TODO: set gBFPlatformLastError - lpNumberOfBytesWritten = 0; - return false; - } - - *lpNumberOfBytesWritten = (uint32)writeCount; - return true; -}*/ - -int64 Beefy::GetFileTimeWrite(const StringImpl& path) -{ - struct stat statbuf = {0}; - int result = stat(path.c_str(), &statbuf); - if (result == -1) - return 0; - - //int64 fileTime = 0; - //BFSystemTimeToFileTime(statbuf.st_mtime, 0, &fileTime); - return statbuf.st_mtime; -} - -/*DWORD GetTimeZoneInformation(TIME_ZONE_INFORMATION* lpTimeZoneInformation) -{ - std::wstring tzName0 = Beefy::UTF8Decode(tzname[0]); - std::wstring tzName1 = Beefy::UTF8Decode(tzname[1]); - - bool isDST = false; - - time_t timeNow; - time(&timeNow); - tm tmNow = *gmtime(&timeNow); - isDST = tmNow.tm_isdst; - - struct tm checkTM; - memset(&checkTM, 0, sizeof(tm)); - checkTM.tm_mday = 1; - checkTM.tm_year = tmNow.tm_year; - time_t checkTime = mktime(&checkTM); - - time_t lastOffset = 0; - time_t minOffset = 0; - time_t maxOffset = 0; - - for (int pass = 0; pass < 2; pass++) - { - int searchDir = 60*60*24; - int thresholdCount = 0; - - while (true) - { - checkTime += searchDir; - - tm checkTM = *gmtime(&checkTime); - - if (checkTM.tm_year != tmNow.tm_year) - break; // No DST - - mktime(&checkTM); - - time_t offset = checkTM.tm_gmtoff; - if (lastOffset != offset) - { - if (thresholdCount == 0) - { - minOffset = offset; - maxOffset = offset; - } - else if (thresholdCount == 3) - { - SYSTEMTIME* sysTimeP = (offset == minOffset) ? - &lpTimeZoneInformation->StandardDate : - &lpTimeZoneInformation->DaylightDate; - - if (offset == minOffset) - tzName0 = Beefy::UTF8Decode(checkTM.tm_zone); - else - tzName1 = Beefy::UTF8Decode(checkTM.tm_zone); - - sysTimeP->wDay = 0; - sysTimeP->wDayOfWeek = 0; - sysTimeP->wYear = checkTM.tm_year + 1900; - sysTimeP->wMonth = checkTM.tm_mon; - sysTimeP->wDay = checkTM.tm_mday + 1; - sysTimeP->wHour = checkTM.tm_hour; - sysTimeP->wMinute = checkTM.tm_min; - sysTimeP->wSecond = checkTM.tm_sec; - sysTimeP->wMilliseconds = 0; - - break; - } - else - { - if (thresholdCount == 1) - searchDir /= -24; - else - searchDir /= -60; - minOffset = std::min(minOffset, offset); - maxOffset = std::max(maxOffset, offset); - } - thresholdCount++; - lastOffset = offset; - } - } - } - - wcsncpy(lpTimeZoneInformation->StandardName, tzName0.c_str(), 32); - wcsncpy(lpTimeZoneInformation->DaylightName, tzName1.c_str(), 32); - - lpTimeZoneInformation->DaylightBias = (int32)maxOffset; - lpTimeZoneInformation->StandardBias = (int32)minOffset; - - if (minOffset == maxOffset) - return 0; - return isDST ? 2 : 1; -}*/ - -bool Beefy::FileExists(const StringImpl& path, String* outActualName) -{ - struct stat statbuf = {0}; - int result = stat(path.c_str(), &statbuf); - if (result != 0) - return false; - return !S_ISDIR(statbuf.st_mode); -} - -bool Beefy::DirectoryExists(const StringImpl& path, String* outActualName) -{ - struct stat statbuf = {0}; - int result = stat(path.c_str(), &statbuf); - if (result != 0) - return false; - return S_ISDIR(statbuf.st_mode); -} - -uint64 Beefy::BFGetTickCountMicro() -{ - struct timespec now; - if (clock_gettime(CLOCK_MONOTONIC, &now)) - return 0; - return ((uint64)now.tv_sec * 1000000.0 + (uint64)now.tv_nsec / 1000); -} - -uint64 Beefy::BFGetTickCountMicroFast() -{ - return BFGetTickCountMicro(); -} - -/* -int64 abs(int64 val) -{ - return llabs(val); -} -*/ -void mkdir(const char* path) -{ - mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); -} - -typedef void(*CrashInfoFunc)(); - -static CritSect gSysCritSect; -static String gCrashInfo; -static Array gCrashInfoFuncs; - -struct bt_ctx { - struct backtrace_state *state; - int error; -}; - -static void error_callback(void *data, const char *msg, int errnum) -{ - struct bt_ctx *ctx = (bt_ctx*)data; - fprintf(stderr, "ERROR: %s (%d)", msg, errnum); - ctx->error = 1; -} - -static void syminfo_callback (void *data, uintptr_t pc, const char *symname, uintptr_t symval, uintptr_t symsize) -{ - char str[4096]; - if (symname) - stbsp_snprintf(str, 4096, "%@ %s\n", pc, symname); - else - stbsp_snprintf(str, 4096, "%@\n", pc); - fputs(str, stderr); -} - -static int full_callback(void *data, uintptr_t pc, const char* filename, int lineno, const char* function) -{ - struct bt_ctx *ctx = (bt_ctx*)data; - if (function) - { - int status = -1; - char* demangledName = abi::__cxa_demangle(function, NULL, NULL, &status ); - const char* showName = (demangledName != NULL) ? demangledName : function; - - char str[4096]; - stbsp_snprintf(str, 4096, "%@ %s %s:%d\n", pc, showName, filename?filename:"??", lineno); - fputs(str, stderr); - - if (demangledName != NULL) - free(demangledName); - } - else - backtrace_syminfo (ctx->state, pc, syminfo_callback, error_callback, data); - return 0; -} - -static int simple_callback(void *data, uintptr_t pc) -{ - struct bt_ctx *ctx = (bt_ctx*)data; - backtrace_pcinfo(ctx->state, pc, full_callback, error_callback, data); - return 0; -} - -static inline void bt(struct backtrace_state *state) -{ - struct bt_ctx ctx = {state, 0}; - //backtrace_print(state, 0, stdout); - backtrace_simple(state, 2, simple_callback, error_callback, &ctx); -} - -static String gCmdLine; -static String gExePath; - -static void Crashed() -{ - // - { - AutoCrit autoCrit(gSysCritSect); - - String debugDump; - - debugDump += "**** FATAL APPLICATION ERROR ****\n"; - - for (auto func : gCrashInfoFuncs) - func(); - - if (!gCrashInfo.IsEmpty()) - { - debugDump += gCrashInfo; - debugDump += "\n"; - } - - fprintf(stderr, "%s", debugDump.c_str()); - } - - struct backtrace_state *state = backtrace_create_state(gExePath.c_str(), BACKTRACE_SUPPORTS_THREADS, error_callback, NULL); - bt(state); - - /*void* array[10]; - size_t size; - char** strings; - size_t i; - - size = backtrace(array, 10); - strings = backtrace_symbols(array, size); - - for (i = 0; i < size; i++) - fprintf(stderr, "%s\n", strings[i]); - - free(strings);*/ - - exit(1); -} - -static void SigHandler(int sig) -{ - //printf("SigHandler paused...\n"); - - const char* sigName = NULL; - switch (sig) - { - case SIGFPE: - sigName = "SIGFPE"; - break; - case SIGSEGV: - sigName = "SIGSEGV"; - break; - case SIGABRT: - sigName = "SIGABRT"; - break; - case SIGILL: - sigName = "SIGILL"; - break; - } - - if (sigName != NULL) - gCrashInfo += StrFormat("Signal: %s\n", sigName); - else - gCrashInfo += StrFormat("Signal: %d\n", sig); - Crashed(); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_Init(int version, BfpSystemInitFlags flags) -{ - if (version != BFP_VERSION) - { - BfpSystem_FatalError(StrFormat("Bfp build version '%d' does not match requested version '%d'", BFP_VERSION, version).c_str(), "BFP FATAL ERROR"); - } - - signal(SIGSEGV, SigHandler); - signal(SIGFPE, SigHandler); - signal(SIGABRT, SigHandler); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCommandLine(int argc, char** argv) -{ - char* relPath = argv[0]; - - char* cwd = getcwd(NULL, 0); - gExePath = GetAbsPath(relPath, cwd); - free(cwd); - - for (int i = 0; i < argc; i++) - { - if (i != 0) - gCmdLine.Append(' '); - - String arg = argv[i]; - if ((arg.Contains(' ')) || (arg.Contains('\"'))) - { - arg.Replace("\"", "\\\""); - gCmdLine.Append("\""); - gCmdLine.Append(arg); - gCmdLine.Append("\""); - } - else - gCmdLine.Append(arg); - } -} - - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCrashReportKind(BfpCrashReportKind crashReportKind) -{ - -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfoFunc(BfpCrashInfoFunc crashInfoFunc) -{ - AutoCrit autoCrit(gSysCritSect); - gCrashInfoFuncs.Add(crashInfoFunc); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfo(const char* str) // Can do at any time, or during CrashInfoFunc callbacks -{ - AutoCrit autoCrit(gSysCritSect); - gCrashInfo.Append(str); -} - -void BfpSystem_Shutdown() -{ - -} - -BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_TickCount() -{ - return Beefy::BFTickCount(); -} - -BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpSystem_GetTimeStamp() -{ - struct timeval tv; - BfpTimeStamp result = 11644473600LL; - gettimeofday(&tv, NULL); - result += tv.tv_sec; - result *= 10000000LL; - result += tv.tv_usec * 10; - return result; -} - -BFP_EXPORT uint16 BFP_CALLTYPE BfpSystem_EndianSwap16(uint16 val) -{ - return __builtin_bswap16(val); -} - -BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_EndianSwap32(uint32 val) -{ - return __builtin_bswap32(val); -} - -BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_EndianSwap64(uint64 val) -{ - return __builtin_bswap64(val); -} - -BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedExchange32(uint32* ptr, uint32 val) -{ - // __sync_lock_test_and_set only has Acquire semantics, so we need a __sync_synchronize to enforce a full barrier - uint32 prevVal = __sync_lock_test_and_set(ptr, val); - __sync_synchronize(); - return prevVal; -} - -BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedExchange64(uint64* ptr, uint64 val) -{ - // __sync_lock_test_and_set only has Acquire semantics, so we need a __sync_synchronize to enforce a full barrier - uint64 prevVal = __sync_lock_test_and_set(ptr, val); - __sync_synchronize(); - return prevVal; -} - -BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedExchangeAdd32(uint32* ptr, uint32 val) -{ - return __sync_fetch_and_add(ptr, val); -} - -BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedExchangeAdd64(uint64* ptr, uint64 val) -{ - return __sync_fetch_and_add(ptr, val); -} - -BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedCompareExchange32(uint32* ptr, uint32 oldVal, uint32 newVal) -{ - return __sync_val_compare_and_swap(ptr, oldVal, newVal); -} - -BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedCompareExchange64(uint64* ptr, uint64 oldVal, uint64 newVal) -{ - return __sync_val_compare_and_swap(ptr, oldVal, newVal); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_FatalError(const char* error, const char* title) -{ - fprintf(stderr, "%s\n", error); - fflush(stderr); - Crashed(); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetCommandLine(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) -{ - TryStringOut(gCmdLine, outStr, inOutStrSize, (BfpResult*)outResult); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetExecutablePath(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) -{ - TryStringOut(gExePath, outStr, inOutStrSize, (BfpResult*)outResult); -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetEnvironmentStrings(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) -{ - String env; - - char** envPtr = environ; - while (true) - { - char* envStr = *envPtr; - env.Append(envStr, strlen(envStr) + 1); - ++envPtr; - } - - TryStringOut(env, outStr, inOutStrSize, (BfpResult*)outResult); -} - -BFP_EXPORT int BFP_CALLTYPE BfpSystem_GetNumLogicalCPUs(BfpSystemResult* outResult) -{ - OUTRESULT(BfpSystemResult_Ok); - return get_nprocs_conf(); -} - -BFP_EXPORT int64 BFP_CALLTYPE BfpSystem_GetCPUTick() -{ - return 10000000; -} - -BFP_EXPORT int64 BFP_CALLTYPE BfpSystem_GetCPUTickFreq() -{ - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - return (now.tv_sec * 10000000LL) + now.tv_nsec / 100; -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_CreateGUID(BfpGUID* outGuid) -{ -// uuid_t guid; -// uuid_generate(guid); -// BfpGUID bfpGuid; -// memcpy(&bfpGuid, guid, 16); -// return bfpGuid; - - uint8* ptr = (uint8*)outGuid; - - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution dis(0, 255); - for (int i = 0; i < 16; i++) - ptr[i] = dis(gen); - - // variant must be 10xxxxxx - ptr[8] &= 0xBF; - ptr[8] |= 0x80; - - // version must be 0100xxxx - ptr[6] &= 0x4F; - ptr[6] |= 0x40; -} - -BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetComputerName(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) -{ - char hostName[1024]; - gethostname(hostName, 1024); - TryStringOut(hostName, outStr, inOutStrSize, (BfpResult*)outResult); -} - -// BfpProcess - -BFP_EXPORT intptr BFP_CALLTYPE BfpProcess_GetCurrentId() -{ - return getpid(); -} - -BFP_EXPORT bool BFP_CALLTYPE BfpProcess_IsRemoteMachine(const char* machineName) -{ - return false; -} - -BFP_EXPORT BfpProcess* BFP_CALLTYPE BfpProcess_GetById(const char* machineName, int processId, BfpProcessResult* outResult) -{ - NOT_IMPL; - return NULL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpProcess_Enumerate(const char* machineName, BfpProcess** outProcesses, int* inOutProcessesSize, BfpProcessResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpProcess_Release(BfpProcess* process) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpProcess_GetMainWindowTitle(BfpProcess* process, char* outTitle, int* inOutTitleSize, BfpProcessResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpProcess_GetProcessName(BfpProcess* process, char* outName, int* inOutNameSize, BfpProcessResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT int BFP_CALLTYPE BfpProcess_GetProcessId(BfpProcess* process) -{ - NOT_IMPL; - return 0; -} - -// BfpSpawn - -struct BfpSpawn -{ - int mPid; - bool mExited; - int mStatus; - int mStdInFD; - int mStdOutFD; - int mStdErrFD; -}; - -BFP_EXPORT BfpSpawn* BFP_CALLTYPE BfpSpawn_Create(const char* inTargetPath, const char* args, const char* workingDir, const char* env, BfpSpawnFlags flags, BfpSpawnResult* outResult) -{ - Beefy::Array stringViews; - - //printf("Executing: %s %s %x\n", inTargetPath, args, flags); - - if ((workingDir != NULL) && (workingDir[0] != 0)) - { - if (chdir(workingDir) != 0) - { - //printf("CHDIR failed %s\n", workingDir); - OUTRESULT(BfpSpawnResult_UnknownError); - return NULL; - } - } - - String newArgs; - String tempFileName; - - if ((flags & BfpSpawnFlag_UseArgsFile) != 0) - { - char tempFileNameStr[256]; - int size = 256; - BfpFileResult fileResult; - BfpFile_GetTempFileName(tempFileNameStr, &size, &fileResult); - if (fileResult == BfpFileResult_Ok) - { - tempFileName = tempFileNameStr; - - BfpFileResult fileResult; - BfpFile* file = BfpFile_Create(tempFileNameStr, BfpFileCreateKind_CreateAlways, BfpFileCreateFlag_Write, BfpFileAttribute_Normal, &fileResult); - if (file == NULL) - { - OUTRESULT(BfpSpawnResult_TempFileError); - return NULL; - } - - if ((flags & BfpSpawnFlag_UseArgsFile_Native) != 0) - { - UTF16String wStr = UTF8Decode(args); - - if ((flags & BfpSpawnFlag_UseArgsFile_BOM) != 0) - { - uint8 bom[2] = { 0xFF, 0xFE }; - BfpFile_Write(file, bom, 2, -1, NULL); - } - - BfpFile_Write(file, wStr.c_str(), wStr.length() * 2, -1, NULL); - } - else - BfpFile_Write(file, args, strlen(args), -1, NULL); - BfpFile_Release(file); - - newArgs.Append("@"); - newArgs.Append(tempFileName); - if (newArgs.Contains(' ')) - { - newArgs.Insert(0, '\"'); - newArgs.Append('\"'); - } - - args = newArgs.c_str(); - } - } - - int32 firstCharIdx = -1; - bool inQuote = false; - - String targetPath = inTargetPath; - String verb; - if ((flags & BfpSpawnFlag_UseShellExecute) != 0) - { - String target = targetPath; - int barPos = (int)target.IndexOf('|'); - if (barPos != -1) - { - verb = targetPath.Substring(barPos + 1); - targetPath.RemoveToEnd(barPos); - } - } - - int32 i = 0; - for ( ; true; i++) - { - char c = args[i]; - if (c == '\0') - break; - if ((c == ' ') && (!inQuote)) - { - if (firstCharIdx != -1) - { - stringViews.Add(Beefy::StringView(args, firstCharIdx, i - firstCharIdx)); - firstCharIdx = -1; - } - } - else - { - if (firstCharIdx == -1) - firstCharIdx = i; - if (c == '"') - inQuote = !inQuote; - else if ((inQuote) && (c == '\\')) - { - c = args[i + 1]; - if (c == '"') - i++; - } - } - } - if (firstCharIdx != -1) - stringViews.Add(Beefy::StringView(args, firstCharIdx, i - firstCharIdx)); - - Beefy::Array argvArr; - - if ((flags & BfpSpawnFlag_ArgsIncludesTarget) == 0) - argvArr.Add(strdup(targetPath.c_str())); - - for (int32 i = 0; i < (int32)stringViews.size(); i++) - { - Beefy::StringView stringView = stringViews[i]; - char* str = NULL; - for (int32 pass = 0; pass < 2; pass++) - { - char* strPtr = str; - - int32 strPos = 0; - for (int32 char8Idx = 0; char8Idx < stringView.mLength; char8Idx++) - { - char c = stringView.mPtr[char8Idx]; - if (c == '"') - inQuote = !inQuote; - else - { - if ((inQuote) && (c == '\\') && (char8Idx < stringView.mLength - 1)) - { - char nextC = stringView.mPtr[char8Idx + 1]; - if (nextC == '"') - { - c = nextC; - char8Idx++; - } - } - if (strPtr != NULL) - *(strPtr++) = c; - strPos++; - } - } - if (pass == 0) - str = (char*)malloc(strPos + 1); - else - *(strPtr++) = 0; - } - - argvArr.Add(str); - } - argvArr.Add(NULL); - - char** argv = NULL; - - //pid_t pid = 0; - //int status = posix_spawn(&pid, targetPath, NULL, NULL, &argvArr[0], environ); - - Beefy::Array envArr; - if (env != NULL) - { - char* envPtr = (char*)env; - while (true) - { - if (*envPtr == 0) - break; - - envArr.Add(envPtr); - envPtr += strlen(envPtr) + 1; - } - } - envArr.Add(NULL); - - int stdInFD[2]; - int stdOutFD[2]; - int stdErrFD[2]; - - bool failed = false; - if ((flags & BfpSpawnFlag_RedirectStdInput) != 0) - if (pipe(stdInFD) != 0) - failed = true; - if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0) - if (pipe(stdOutFD) != 0) - failed = true; - if ((flags & BfpSpawnFlag_RedirectStdError) != 0) - if (pipe(stdErrFD) != 0) - failed = true; - if (failed) - { - //printf("Pipe failed\n"); - OUTRESULT(BfpSpawnResult_UnknownError); - return NULL; - } - - BfpSpawn* spawn; - pid_t pid = fork(); - if (pid == -1) // Error - { - OUTRESULT(BfpSpawnResult_UnknownError); - return NULL; - } - else if (pid == 0) // Child - { - if ((flags & BfpSpawnFlag_RedirectStdInput) != 0) - while ((dup2(stdInFD[0], STDIN_FILENO) == -1) && (errno == EINTR)) {} - if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0) - while ((dup2(stdOutFD[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {} - if ((flags & BfpSpawnFlag_RedirectStdError) != 0) - while ((dup2(stdErrFD[1], STDERR_FILENO) == -1) && (errno == EINTR)) {} - - // If successful then this shouldn't return at all: - int result; - - if (env != NULL) - result = execve(targetPath.c_str(), (char* const*)&argvArr[0], (char* const*)&envArr[0]); - else - result = execv(targetPath.c_str(), (char* const*)&argvArr[0]); - - printf("Couldn't execute %s\n", targetPath.c_str()); - - exit(-1); - } - else // Parent - { - spawn = new BfpSpawn(); - - if ((flags & BfpSpawnFlag_RedirectStdInput) != 0) - { - spawn->mStdInFD = stdInFD[1]; - close(stdInFD[0]); - } - else - spawn->mStdInFD = 0; - - if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0) - { - spawn->mStdOutFD = stdOutFD[0]; - close(stdOutFD[1]); - } - else - spawn->mStdOutFD = 0; - - if ((flags & BfpSpawnFlag_RedirectStdError) != 0) - { - spawn->mStdErrFD = stdErrFD[0]; - close(stdErrFD[1]); - } - else - spawn->mStdErrFD = 0; - } - - for (auto val : argvArr) - free(val); - - //printf("Spawn pid:%d status:%d\n", pid, status); - spawn->mPid = pid; - spawn->mExited = false; - spawn->mStatus = 0; - - return spawn; -} - -void BfpSpawn_Release(BfpSpawn* spawn) -{ - // We don't support 'detaching' currently- this can create zombie processes since we - // don't have a reaper strategy - BfpSpawn_WaitFor(spawn, -1, NULL, NULL); - - delete spawn; -} - -BFP_EXPORT void BFP_CALLTYPE BfpSpawn_GetStdHandles(BfpSpawn* spawn, BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr) -{ - if (outStdIn != NULL) - { - *outStdIn = new BfpFile(spawn->mStdInFD); - spawn->mStdInFD = 0; - } - - if (outStdOut != NULL) - { - *outStdOut = new BfpFile(spawn->mStdOutFD); - spawn->mStdOutFD = 0; - } - - if (outStdErr != NULL) - { - *outStdErr = new BfpFile(spawn->mStdErrFD); - spawn->mStdErrFD = 0; - } -} - -bool BfpSpawn_WaitFor(BfpSpawn* spawn, int waitMS, int* outExitCode, BfpSpawnResult* outResult) -{ - OUTRESULT(BfpSpawnResult_Ok); - if (!spawn->mExited) - { - int flags = 0; - if (waitMS != -1) - { - flags = WNOHANG; - } - //TODO: Implement values other than 0 or -1 for waitMS? - - pid_t result = waitpid(spawn->mPid, &spawn->mStatus, flags); - if (result != spawn->mPid) - return false; - - spawn->mExited = true; - } - - if (!WIFEXITED(spawn->mStatus) && !WIFSIGNALED(spawn->mStatus)) - return false; - - if (outExitCode != NULL) - *outExitCode = WEXITSTATUS(spawn->mStatus); - return true; -} - -// BfpFileWatcher - -BFP_EXPORT BfpFileWatcher* BFP_CALLTYPE BfpFileWatcher_WatchDirectory(const char* path, BfpDirectoryChangeFunc callback, BfpFileWatcherFlags flags, void* userData, BfpFileResult* outResult) -{ - NOT_IMPL; - return NULL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFileWatcher_Release(BfpFileWatcher* fileWatcher) -{ - NOT_IMPL; -} - -// BfpThread - -struct BfpThread -{ - bool mPThreadReleased; - BfpThreadStartProc mStartProc; - void* mThreadParam; - - pthread_t mPThread; - int mRefCount; - int mPriority; - - BfpThread() - { - } - - void Release() - { - int refCount = __sync_fetch_and_sub(&mRefCount, 1) - 1; - if (refCount == 0) - delete this; - } -}; - -struct BfpThreadInfo -{ - intptr mStackBase; - int mStackLimit; -}; - -static __thread BfpThread* gCurrentThread; -static __thread BfpThreadInfo gCurrentThreadInfo; - -void* ThreadFunc(void* threadParam) -{ - BfpThread* thread = (BfpThread*)threadParam; - gCurrentThread = thread; - thread->mStartProc(thread->mThreadParam); - thread->Release(); -} - -BFP_EXPORT BfpThread* BFP_CALLTYPE BfpThread_Create(BfpThreadStartProc startProc, void* threadParam, intptr stackSize, BfpThreadCreateFlags flags, BfpThreadId* outThreadId) -{ - BfpThread* thread = new BfpThread(); - thread->mPThreadReleased = false; - thread->mStartProc = startProc; - thread->mThreadParam = threadParam; - thread->mRefCount = 2; - thread->mPriority = 0; - - BF_ASSERT(sizeof(pthread_t) <= sizeof(void*)); - pthread_attr_t params; - pthread_attr_init(¶ms); - pthread_attr_setstacksize(¶ms, stackSize); - //pthread_attr_setdetachstate(¶ms,PTHREAD_CREATE_DETACHED); - - pthread_create(&thread->mPThread, ¶ms, ThreadFunc, (void*)thread); - - pthread_attr_destroy(¶ms); - - if (outThreadId != NULL) - *outThreadId = (BfpThreadId)thread->mPThread; - - return thread; -} - -#define FIXTHREAD() \ - pthread_t pt; \ - if (((intptr)thread & 1) != 0) \ - { \ - pt = (pthread_t)((intptr)thread & ~3); \ - thread = NULL; \ - } else \ - pt = thread->mPThread - -BFP_EXPORT void BFP_CALLTYPE BfpThread_Release(BfpThread* thread) -{ - FIXTHREAD(); - if (thread == NULL) - return; - - if (!thread->mPThreadReleased) - { - pthread_detach(thread->mPThread); - thread->mPThreadReleased = true; - } - thread->Release(); -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_SetName(BfpThread* thread, const char* name, BfpThreadResult* outResult) -{ - OUTRESULT(BfpThreadResult_Ok); -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_GetName(BfpThread* thread, char* outName, int* inOutNameSize, BfpThreadResult* outResult) -{ - String str = ""; - TryStringOut(str, outName, inOutNameSize, (BfpResult*)outResult); -} - -BFP_EXPORT BfpThread* BFP_CALLTYPE BfpThread_GetCurrent() -{ - if (gCurrentThread == NULL) - { - // Not a "true" BfpThread, this is either the main thread or a thread we didn't create - return (BfpThread*)((intptr)pthread_self() | 1); - } - return gCurrentThread; -} - -BFP_EXPORT BfpThreadId BFP_CALLTYPE BfpThread_GetCurrentId() -{ - if (gCurrentThread == NULL) - { - return (BfpThreadId)((intptr)pthread_self()); - } - return (BfpThreadId)gCurrentThread->mPThread; -} - -BFP_EXPORT bool BFP_CALLTYPE BfpThread_WaitFor(BfpThread* thread, int waitMS) -{ - FIXTHREAD(); - - if (waitMS == -1) - { - pthread_join(pt, NULL); - thread->mPThreadReleased = true; - return true; - } - - struct timespec waitTime; - waitTime.tv_sec = waitMS / 1000; - waitTime.tv_nsec = (waitMS % 1000) * 1000000; - int result = pthread_timedjoin_np(pt, NULL, &waitTime); - if (result == 0) - { - if (thread != NULL) - thread->mPThreadReleased = true; - return true; - } - return false; -} - -BFP_EXPORT void BFP_CALLTYPE BfpSpawn_Kill(BfpSpawn* spawn, int exitCode, BfpKillFlags killFlags, BfpSpawnResult* outResult) -{ - //TODO: Implement - OUTRESULT(BfpSpawnResult_UnknownError); -} - -BFP_EXPORT BfpThreadPriority BFP_CALLTYPE BfpThread_GetPriority(BfpThread* thread, BfpThreadResult* outResult) -{ - FIXTHREAD(); - - OUTRESULT(BfpThreadResult_Ok); - if (thread == NULL) - return (BfpThreadPriority)0; - - return (BfpThreadPriority)thread->mPriority; -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_SetPriority(BfpThread* thread, BfpThreadPriority threadPriority, BfpThreadResult* outResult) -{ - // In effect, we have two 'nice' settings: 0 (normal) or 10 (low) - // High-priority settings just don't do anything - //pid_t tid = syscall(SYS_gettid); - //int ret = setpriority(PRIO_PROCESS, tid, -std::min(nPriority, 0) * 10); - OUTRESULT(BfpThreadResult_Ok); -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_Suspend(BfpThread* thread, BfpThreadResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_Resume(BfpThread* thread, BfpThreadResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_GetIntRegisters(BfpThread* thread, intptr* outStackPtr, intptr* outIntRegs, int* inOutIntRegCount, BfpThreadResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_GetStackInfo(BfpThread* thread, intptr* outStackBase, int* outStackLimit, BfpThreadResult* outResult) -{ - if (gCurrentThreadInfo.mStackBase == 0) - { - void* stackBase = 0; - size_t stackLimit = 0; - - pthread_attr_t attr; - pthread_getattr_np(pthread_self(), &attr); - pthread_attr_getstack(&attr, &stackBase, &stackLimit); - - gCurrentThreadInfo.mStackBase = (intptr)stackBase + stackLimit; - gCurrentThreadInfo.mStackLimit = (int)stackLimit; - pthread_attr_destroy(&attr); - } - - *outStackBase = gCurrentThreadInfo.mStackBase; - *outStackLimit = gCurrentThreadInfo.mStackLimit; - - OUTRESULT(BfpThreadResult_Ok); -} - -BFP_EXPORT void BFP_CALLTYPE BfpThread_Sleep(int sleepMS) -{ - usleep(sleepMS * 1000); -} - -BFP_EXPORT bool BFP_CALLTYPE BfpThread_Yield() -{ - return sched_yield() == 0; -} - -struct BfpCritSect -{ - pthread_mutex_t mPMutex; -}; - -BFP_EXPORT BfpCritSect* BFP_CALLTYPE BfpCritSect_Create() -{ - BfpCritSect* critSect = new BfpCritSect(); - - pthread_mutexattr_t attributes; - pthread_mutexattr_init(&attributes); - pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&critSect->mPMutex, &attributes); - pthread_mutexattr_destroy(&attributes); - - return critSect; -} - -BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Release(BfpCritSect* critSect) -{ - pthread_mutex_destroy(&critSect->mPMutex); -} - -BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Enter(BfpCritSect* critSect) -{ - pthread_mutex_lock(&critSect->mPMutex); -} - -BFP_EXPORT bool BFP_CALLTYPE BfpCritSect_TryEnter(BfpCritSect* critSect, int waitMS) -{ - if (waitMS == -1) - { - BfpCritSect_Enter(critSect); - return true; - } - else if (waitMS == 0) - { - return pthread_mutex_trylock(&critSect->mPMutex) == 0; - } - - uint32 start = Beefy::BFTickCount(); - while ((int)(Beefy::BFTickCount() - start) < waitMS) - { - if (pthread_mutex_trylock(&critSect->mPMutex) == 0) - { - return true; - } - } - return false; -} - -BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Leave(BfpCritSect* critSect) -{ - pthread_mutex_unlock(&critSect->mPMutex); -} - -BFP_EXPORT BfpTLS* BFP_CALLTYPE BfpTLS_Create() -{ - pthread_key_t key = 0; - pthread_key_create(&key, NULL); - return (BfpTLS*)(intptr)key; -} - -BFP_EXPORT void BFP_CALLTYPE BfpTLS_Release(BfpTLS* tls) -{ - pthread_key_delete((pthread_key_t)(intptr)tls); -} - -BFP_EXPORT void BFP_CALLTYPE BfpTLS_SetValue(BfpTLS* tls, void* value) -{ - pthread_setspecific((pthread_key_t)(intptr)tls, value); -} - -BFP_EXPORT void* BFP_CALLTYPE BfpTLS_GetValue(BfpTLS* tls) -{ - return pthread_getspecific((pthread_key_t)(intptr)tls); -} - -struct BfpEvent -{ - pthread_mutex_t mMutex; - pthread_cond_t mCondVariable; - bool mSet; - bool mManualReset; -}; - -BFP_EXPORT BfpEvent* BFP_CALLTYPE BfpEvent_Create(BfpEventFlags flags) -{ - BfpEvent* event = new BfpEvent(); - pthread_mutex_init(&event->mMutex, NULL); - pthread_cond_init(&event->mCondVariable, NULL); - event->mSet = (flags & (BfpEventFlag_InitiallySet_Auto | BfpEventFlag_InitiallySet_Manual)) != 0; - event->mManualReset = (flags & BfpEventFlag_InitiallySet_Manual) != 0; - return event; -} - -BFP_EXPORT void BFP_CALLTYPE BfpEvent_Release(BfpEvent* event) -{ - pthread_cond_destroy(&event->mCondVariable); - pthread_mutex_destroy(&event->mMutex); -} - -BFP_EXPORT void BFP_CALLTYPE BfpEvent_Set(BfpEvent* event, bool requireManualReset) -{ - pthread_mutex_lock(&event->mMutex); - event->mSet = true; - if (requireManualReset) - event->mManualReset = true; - if (event->mManualReset) - pthread_cond_broadcast(&event->mCondVariable); - else - pthread_cond_signal(&event->mCondVariable); - pthread_mutex_unlock(&event->mMutex); -} - -BFP_EXPORT void BFP_CALLTYPE BfpEvent_Reset(BfpEvent* event, BfpEventResult* outResult) -{ - event->mSet = false; - event->mManualReset = false; -} - -BFP_EXPORT bool BFP_CALLTYPE BfpEvent_WaitFor(BfpEvent* event, int waitMS) -{ - int result = pthread_mutex_lock(&event->mMutex); - BF_ASSERT(result == 0); - while (!event->mSet) - { - if (waitMS == -1) - { - pthread_cond_wait(&event->mCondVariable, &event->mMutex); - } - else - { - timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - ts.tv_sec += waitMS / 1000; - ts.tv_nsec += (waitMS % 1000) * 1000000; - - result = pthread_cond_timedwait(&event->mCondVariable, &event->mMutex, &ts); - - if (waitMS == (uint32)-1) - BF_ASSERT(result == 0); - - if (result != 0) - { - // Timeout - pthread_mutex_unlock(&event->mMutex); - return false; - } - } - } - if (!event->mManualReset) - event->mSet = false; - pthread_mutex_unlock(&event->mMutex); - return true; -} - -BFP_EXPORT BfpDynLib* BFP_CALLTYPE BfpDynLib_Load(const char* fileName) -{ - BfpDynLib* mod = NULL; - - static const char* prefixes[] = {NULL, "lib"}; - static const char* suffixes[] = {NULL, ".so", ".dylib"}; - - for (int prefixIdx = 0; prefixIdx < sizeof(prefixes)/sizeof(prefixes[0]); prefixIdx++) - { - for (int suffixIdx = 0; suffixIdx < sizeof(suffixes)/sizeof(suffixes[0]); suffixIdx++) - { - const char* prefix = prefixes[prefixIdx]; - const char* suffix = suffixes[suffixIdx]; - - Beefy::String checkName = fileName; - if (prefix != NULL) - checkName = Beefy::String(prefix) + checkName; - if (suffix != NULL) - { - int dotPos = checkName.LastIndexOf('.'); - if (dotPos != -1) - checkName.RemoveToEnd(dotPos); - checkName += suffix; - } - - mod = (BfpDynLib*)dlopen(checkName.c_str(), RTLD_LAZY); - if (mod != NULL) - return mod; - } - } - - /*mod = (BfpDynLib*)dlopen("/var/Beef/qt-build/Debug/bin/libIDEHelper.so", RTLD_LAZY);; - if (mod == NULL) - { - printf("Err: %s\n", dlerror()); - fflush(stdout); - }*/ - - return NULL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpDynLib_Release(BfpDynLib* lib) -{ - dlclose((void*)lib); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDynLib_GetFilePath(BfpDynLib* lib, char* outPath, int* inOutPathSize, BfpLibResult* outResult) -{ - Beefy::String path; - - link_map* linkMap = NULL; - dlinfo((void*)lib, RTLD_DI_LINKMAP, &linkMap); - if (linkMap == NULL) - { - OUTRESULT(BfpLibResult_UnknownError); - return; - } - - path = linkMap->l_name; - TryStringOut(path, outPath, inOutPathSize, (BfpResult*)outResult); -} - -BFP_EXPORT void* BFP_CALLTYPE BfpDynLib_GetProcAddress(BfpDynLib* lib, const char* name) -{ - return dlsym((void*)lib, name); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Create(const char* path, BfpFileResult* outResult) -{ - if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) - { - switch (errno) - { - case EEXIST: - OUTRESULT(BfpFileResult_AlreadyExists); - break; - case ENOENT: - OUTRESULT(BfpFileResult_NotFound); - break; - default: - OUTRESULT(BfpFileResult_UnknownError); - break; - } - } - else - OUTRESULT(BfpFileResult_Ok); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Rename(const char* oldName, const char* newName, BfpFileResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Delete(const char* path, BfpFileResult* outResult) -{ - if (rmdir(path) != 0) - { - switch (errno) - { - case ENOENT: - OUTRESULT(BfpFileResult_NotFound); - break; - default: - OUTRESULT(BfpFileResult_UnknownError); - break; - } - } - else - OUTRESULT(BfpFileResult_Ok); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_GetCurrent(char* outPath, int* inOutPathSize, BfpFileResult* outResult) -{ - char* str = getcwd(NULL, 0); - Beefy::String path = str; - free(str); - TryStringOut(path, outPath, inOutPathSize, (BfpResult*)outResult); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_SetCurrent(const char* path, BfpFileResult* outResult) -{ - if (chdir(path) != 0) - OUTRESULT(BfpFileResult_NotFound); - else - OUTRESULT(BfpFileResult_Ok); -} - -BFP_EXPORT bool BFP_CALLTYPE BfpDirectory_Exists(const char* path) -{ - struct stat statbuf = {0}; - int result = stat(path, &statbuf); - if (result != 0) - return false; - return S_ISDIR(statbuf.st_mode); -} - -BFP_EXPORT void BFP_CALLTYPE BfpDirectory_GetSysDirectory(BfpSysDirectoryKind sysDirKind, char* outPath, int* inOutPathLen, BfpFileResult* outResult) -{ - String path = "~"; - TryStringOut(path, outPath, inOutPathLen, (BfpResult*)outResult); -} - -BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_Create(const char* inName, BfpFileCreateKind createKind, BfpFileCreateFlags createFlags, BfpFileAttributes createdFileAttrs, BfpFileResult* outResult) -{ - auto _DoCreate = [&](String& name) - { - int flags = 0; - int mode = 0; - int pipePairHandle = -1; - - if ((createFlags & (BfpFileCreateFlag_Read | BfpFileCreateFlag_Write)) == (BfpFileCreateFlag_Read | BfpFileCreateFlag_Write)) - flags |= O_RDWR; - else if ((createFlags & BfpFileCreateFlag_Read) != 0) - flags |= O_RDONLY; - else if ((createFlags & BfpFileCreateFlag_Write) != 0) - flags |= O_WRONLY; - - if ((createFlags & BfpFileCreateFlag_Append) != 0) - flags |= O_APPEND; - if ((createFlags & BfpFileCreateFlag_Truncate) != 0) - flags |= O_TRUNC; - if ((createFlags & (BfpFileCreateFlag_NonBlocking | BfpFileCreateFlag_AllowTimeouts)) != 0) - flags |= O_NONBLOCK; - - if ((createFlags & BfpFileCreateFlag_Pipe) != 0) - { - name = "/tmp/" + name; - if ((createKind == BfpFileCreateKind_CreateAlways) || - (createKind == BfpFileCreateKind_CreateIfNotExists)) - { - for (int pass = 0; pass < 2; pass++) - { - int result = mknod(name.c_str(), S_IFIFO | 0666, 0); - if (result == 0) - break; - - int err = errno; - if (err == EEXIST) - { - err = remove(name.c_str()); - if (err == 0) - continue; - OUTRESULT(BfpFileResult_AlreadyExists); - return -1; - } - - OUTRESULT(BfpFileResult_UnknownError); - return -1; - } - } - } - else - { - if (createKind == BfpFileCreateKind_CreateAlways) - flags |= O_CREAT; - else if (createKind == BfpFileCreateKind_CreateIfNotExists) - flags |= O_CREAT | O_EXCL; - } - - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; - - int result = open(name.c_str(), flags, mode); - //printf("BfpFile_Create %s %d %d %d\n", name.c_str(), result, flags, mode); - - if (result <= 0) - { - switch (errno) - { - case EEXIST: - OUTRESULT(BfpFileResult_AlreadyExists); - break; - case ENOENT: - OUTRESULT(BfpFileResult_NotFound); - break; - case EACCES: - OUTRESULT(BfpFileResult_AccessError); - break; - default: - OUTRESULT(BfpFileResult_UnknownError); - break; - } - return -1; - } - return result; - }; - - BfpFile* bfpFile = NULL; - - int result; - if ((createFlags & BfpFileCreateFlag_Pipe) != 0) - { - int readHandle; - int writeHandle; - - String name = inName; - String altName = name + "__"; - - bool isCreating = false; - if ((createKind == BfpFileCreateKind_CreateAlways) || - (createKind == BfpFileCreateKind_CreateIfNotExists)) - { - readHandle = _DoCreate(name); - writeHandle = _DoCreate(altName); - isCreating = true; - } - else - { - readHandle = _DoCreate(altName); - writeHandle = _DoCreate(name); - } - - if ((readHandle != -1) && (writeHandle != -1)) - { - OUTRESULT(BfpFileResult_Ok); - - BfpPipeInfo* pipeInfo = new BfpPipeInfo(); - pipeInfo->mWriteHandle = writeHandle; - if (isCreating) - pipeInfo->mPipePath = name; - bfpFile = new BfpFile(); - bfpFile->mHandle = readHandle; - bfpFile->mPipeInfo = pipeInfo; - } - else - { - if (readHandle != -1) - close(readHandle); - if (writeHandle != -1) - close(writeHandle); - - return NULL; - } - } - else - { - String name = inName; - int handle = _DoCreate(name); - if (handle == -1) - return NULL; - - OUTRESULT(BfpFileResult_Ok); - bfpFile = new BfpFile(); - bfpFile->mHandle = handle; - } - - OUTRESULT(BfpFileResult_Ok); - if ((createFlags & (BfpFileCreateFlag_NonBlocking | BfpFileCreateFlag_AllowTimeouts)) != 0) - bfpFile->mNonBlocking = true; - if ((createFlags & BfpFileCreateFlag_AllowTimeouts) != 0) - bfpFile->mAllowTimeout = true; - return bfpFile; -} - -BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult) -{ - int h = -1; - switch (kind) - { - case BfpFileStdKind_StdOut: - h = STDOUT_FILENO; - break; - case BfpFileStdKind_StdError: - h = STDERR_FILENO; - break; - case BfpFileStdKind_StdIn: - h = STDIN_FILENO; - break; - } - if (h == -1) - { - OUTRESULT(BfpFileResult_NotFound); - return NULL; - } - - BfpFile* bfpFile = new BfpFile(); - bfpFile->mHandle = h; - bfpFile->mIsStd = true; - - return bfpFile; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Release(BfpFile* file) -{ - if ((file->mHandle != -1) && (!file->mIsStd)) - close(file->mHandle); - if (file->mPipeInfo != NULL) - { - if (file->mPipeInfo->mWriteHandle != -1) - close(file->mPipeInfo->mWriteHandle); - - if (!file->mPipeInfo->mPipePath.IsEmpty()) - { - int worked = remove(file->mPipeInfo->mPipePath.c_str()); - remove((file->mPipeInfo->mPipePath + "__").c_str()); - //printf("Removing %s %d\n", file->mPipeInfo->mPipePath.c_str(), worked); - } - } - - delete file; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Close(BfpFile* file, BfpFileResult* outResult) -{ - if (file->mHandle != -1) - { - close(file->mHandle); - file->mHandle = -1; - if (file->mPipeInfo != NULL) - { - close(file->mPipeInfo->mWriteHandle); - file->mPipeInfo->mWriteHandle = -1; - } - - OUTRESULT(BfpFileResult_Ok); - } - else - OUTRESULT(BfpFileResult_UnknownError); -} - -BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Write(BfpFile* file, const void* buffer, intptr size, int timeoutMS, BfpFileResult* outResult) -{ - int writeHandle = file->mHandle; - if (file->mPipeInfo != NULL) - writeHandle = file->mPipeInfo->mWriteHandle; - - intptr writeCount = ::write(writeHandle, buffer, size); -// if ((writeCount > 0) && (file->mIsPipe)) -// { -// ::fsync(file->mHandle); -// } - - if (writeCount < 0) - OUTRESULT(BfpFileResult_UnknownError); - else if (writeCount != size) - OUTRESULT(BfpFileResult_PartialData); - else - OUTRESULT(BfpFileResult_Ok); - return writeCount; -} - -BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Read(BfpFile* file, void* buffer, intptr size, int timeoutMS, BfpFileResult* outResult) -{ - if (file->mNonBlocking) - { - if (!file->mAllowTimeout) - timeoutMS = -1; - - timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = timeoutMS * 1000; - - fd_set readFDSet; - FD_ZERO(&readFDSet); - FD_SET(file->mHandle, &readFDSet); - - fd_set errorFDSet; - FD_ZERO(&errorFDSet); - FD_SET(file->mHandle, &errorFDSet); - - if (select(file->mHandle + 1, &readFDSet, NULL, &errorFDSet, (timeoutMS == -1) ? NULL : &timeout) < 0) - { - OUTRESULT(BfpFileResult_Timeout); - return 0; - } - } - - intptr readCount = ::read(file->mHandle, buffer, size); - if (readCount < 0) - OUTRESULT(BfpFileResult_UnknownError); - else if (readCount != size) - OUTRESULT(BfpFileResult_PartialData); - else - OUTRESULT(BfpFileResult_Ok); - return readCount; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Flush(BfpFile* file) -{ - ::fsync(file->mHandle); -} - -BFP_EXPORT int64 BFP_CALLTYPE BfpFile_GetFileSize(BfpFile* file) -{ - int64 oldPos = (int64)lseek64(file->mHandle, 0, SEEK_CUR); - int64 size = (int64)lseek64(file->mHandle, 0, SEEK_END); - lseek64(file->mHandle, oldPos, SEEK_SET); - return (int64)size; -} - -BFP_EXPORT int64 BFP_CALLTYPE BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind) -{ - int whence; - if (seekKind == BfpFileSeekKind_Absolute) - whence = SEEK_SET; - else if (seekKind == BfpFileSeekKind_Relative) - whence = SEEK_CUR; - else - whence = SEEK_END; - return lseek64(file->mHandle, offset, whence); -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Truncate(BfpFile* file) -{ - int64 curPos = (int64)lseek64(file->mHandle, 0, SEEK_CUR); - if (ftruncate64(file->mHandle, curPos) != 0) - { - //TODO: Report error? - } -} - -BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFile_GetTime_LastWrite(const char* path) -{ - struct stat statbuf = {0}; - int result = stat(path, &statbuf); - if (result != 0) - return 0; - return statbuf.st_mtime; -} - -BFP_EXPORT BfpFileAttributes BFP_CALLTYPE BfpFile_GetAttributes(const char* path, BfpFileResult* outResult) -{ - NOT_IMPL; - return (BfpFileAttributes)0; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_SetAttributes(const char* path, BfpFileAttributes attribs, BfpFileResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Copy(const char* oldPath, const char* newPath, BfpFileCopyKind copyKind, BfpFileResult* outResult) -{ - int fd_to, fd_from; - char buf[4096]; - ssize_t nread; - - fd_from = open(oldPath, O_RDONLY); - if (fd_from < 0) - { - OUTRESULT(BfpFileResult_NotFound); - return; - } - - int flags = O_WRONLY | O_CREAT; - if (copyKind == BfpFileCopyKind_IfNotExists) - flags |= O_EXCL; - - fd_to = open(newPath, flags, 0666); - if (fd_to < 0) - { - if (errno == EEXIST) - { - OUTRESULT(BfpFileResult_AlreadyExists); - goto out_error; - } - - OUTRESULT(BfpFileResult_UnknownError); - goto out_error; - } - - while (nread = read(fd_from, buf, sizeof buf), nread > 0) - { - char *out_ptr = buf; - ssize_t nwritten; - - do { - nwritten = write(fd_to, out_ptr, nread); - - if (nwritten >= 0) - { - nread -= nwritten; - out_ptr += nwritten; - } - else if (errno != EINTR) - { - OUTRESULT(BfpFileResult_UnknownError); - goto out_error; - } - } while (nread > 0); - } - - if (nread == 0) - { - if (close(fd_to) < 0) - { - fd_to = -1; - OUTRESULT(BfpFileResult_UnknownError); - goto out_error; - } - close(fd_from); - - /* Success! */ - OUTRESULT(BfpFileResult_Ok); - return; - } - -out_error: - close(fd_from); - if (fd_to >= 0) - close(fd_to); -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Rename(const char* oldPath, const char* newPath, BfpFileResult* outResult) -{ - NOT_IMPL; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_Delete(const char* path, BfpFileResult* outResult) -{ - if (remove(path) != 0) - { - switch (errno) - { - case ENOENT: - OUTRESULT(BfpFileResult_NotFound); - break; - default: - OUTRESULT(BfpFileResult_UnknownError); - break; - } - } - else - OUTRESULT(BfpFileResult_Ok); -} - -BFP_EXPORT bool BFP_CALLTYPE BfpFile_Exists(const char* path) -{ - struct stat statbuf = {0}; - int result = stat(path, &statbuf); - if (result != 0) - return false; - return !S_ISDIR(statbuf.st_mode); -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_GetTempPath(char* outPath, int* inOutPathSize, BfpFileResult* outResult) -{ - NOT_IMPL; -} - -static const char cHash64bToChar[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', - 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', - 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_' }; -static void HashEncode64(StringImpl& outStr, uint64 val) -{ - for (int i = 0; i < 10; i++) - { - int charIdx = (int)((val >> (i * 6)) & 0x3F) - 1; - if (charIdx != -1) - outStr.Append(cHash64bToChar[charIdx]); - } -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_GetTempFileName(char* outName, int* inOutNameSize, BfpFileResult* outResult) -{ - static uint32 uniqueIdx = 0; - BfpSystem_InterlockedExchangeAdd32(&uniqueIdx, 1); - - Beefy::HashContext ctx; - ctx.Mixin(uniqueIdx); - ctx.Mixin(getpid()); - ctx.Mixin(Beefy::BFGetTickCountMicro()); - - uint64 hash = ctx.Finish64(); - - String str = "/tmp/bftmp_"; - HashEncode64(str, hash); - - TryStringOut(str, outName, inOutNameSize, (BfpResult*)outResult); -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_GetFullPath(const char* inPath, char* outPath, int* inOutPathSize, BfpFileResult* outResult) -{ - String str; - - if (inPath[0] == '/') - { - str = inPath; - } - else - { - char* cwdPtr = getcwd(NULL, 0); - Beefy::String cwdPath = cwdPtr; - free(cwdPtr); - str = GetAbsPath(inPath, cwdPath); - } - TryStringOut(str, outPath, inOutPathSize, (BfpResult*)outResult); -} - -BFP_EXPORT void BFP_CALLTYPE BfpFile_GetActualPath(const char* inPath, char* outPath, int* inOutPathSize, BfpFileResult* outResult) -{ - NOT_IMPL; -} - -// BfpFindFileData - -struct BfpFindFileData -{ - BfpFindFileFlags mFlags; - DIR* mDirStruct; - Beefy::String mWildcard; - Beefy::String mDirPath; - - dirent* mDirEnt; - bool mHasStat; - struct stat mStat; -}; - -BFP_EXPORT BfpFindFileData* BFP_CALLTYPE BfpFindFileData_FindFirstFile(const char* path, BfpFindFileFlags flags, BfpFileResult* outResult) -{ - Beefy::String findStr = path; - Beefy::String wildcard; - - int lastSlashPos = std::max((int)findStr.LastIndexOf('/'), (int)findStr.LastIndexOf('\\')); - if (lastSlashPos != -1) - { - wildcard = findStr.Substring(lastSlashPos + 1); - findStr = findStr.Substring(0, lastSlashPos); - } - if (wildcard == "*.*") - wildcard = "*"; - - DIR* dir = opendir(findStr.c_str()); - if (dir == NULL) - { - OUTRESULT(BfpFileResult_NotFound); - return NULL; - } - - BfpFindFileData* findData = new BfpFindFileData(); - findData->mFlags = flags; - findData->mDirPath = findStr; - findData->mDirStruct = dir; - findData->mWildcard = wildcard; - findData->mHasStat = false; - findData->mDirEnt = NULL; - - if (!BfpFindFileData_FindNextFile(findData)) - { - OUTRESULT(BfpFileResult_NoResults); - delete findData; - return NULL; - } - - OUTRESULT(BfpFileResult_Ok); - return findData; -} - -static void GetStat(BfpFindFileData* findData) -{ - if (findData->mHasStat) - return; - - Beefy::String filePath = findData->mDirPath + "/" + findData->mDirEnt->d_name; - - findData->mStat = { 0 }; - int result = stat(filePath.c_str(), &findData->mStat); - - findData->mHasStat = true; -} - -static bool BfpFindFileData_CheckFilter(BfpFindFileData* findData) -{ - bool isDir = false; - if (findData->mDirEnt->d_type == DT_DIR) - isDir = true; - if (findData->mDirEnt->d_type == DT_LNK) - { - GetStat(findData); - isDir = S_ISDIR(findData->mStat.st_mode); - } - - if (isDir) - { - if ((findData->mFlags & BfpFindFileFlag_Directories) == 0) - return false; - - if ((strcmp(findData->mDirEnt->d_name, ".") == 0) || (strcmp(findData->mDirEnt->d_name, "..") == 0)) - return false; - } - else - { - if ((findData->mFlags & BfpFindFileFlag_Files) == 0) - return false; - } - - //TODO: Check actual wildcards. - - return true; -} - -BFP_EXPORT bool BFP_CALLTYPE BfpFindFileData_FindNextFile(BfpFindFileData* findData) -{ - while (true) - { - findData->mHasStat = false; - findData->mDirEnt = readdir(findData->mDirStruct); - if (findData->mDirEnt == NULL) - return false; - - if (BfpFindFileData_CheckFilter(findData)) - break; - } - - return true; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFindFileData_GetFileName(BfpFindFileData* findData, char* outName, int* inOutNameSize, BfpFileResult* outResult) -{ - Beefy::String name = findData->mDirEnt->d_name; - TryStringOut(name, outName, inOutNameSize, (BfpResult*)outResult); -} - -BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_LastWrite(BfpFindFileData* findData) -{ - GetStat(findData); - return BfpToTimeStamp(findData->mStat.st_mtim); -} - -BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_Created(BfpFindFileData* findData) -{ - GetStat(findData); - return BfpToTimeStamp(findData->mStat.st_ctim); -} - -BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_Access(BfpFindFileData* findData) -{ - GetStat(findData); - return BfpToTimeStamp(findData->mStat.st_atim); -} - -BFP_EXPORT BfpFileAttributes BFP_CALLTYPE BfpFindFileData_GetFileAttributes(BfpFindFileData* findData) -{ - BfpFileAttributes flags = BfpFileAttribute_None; - if (S_ISDIR(findData->mStat.st_mode)) - flags = (BfpFileAttributes)(flags | BfpFileAttribute_Directory); - if (S_ISREG(findData->mStat.st_mode)) - flags = (BfpFileAttributes)(flags | BfpFileAttribute_Normal); - else if (!S_ISLNK(findData->mStat.st_mode)) - flags = (BfpFileAttributes)(flags | BfpFileAttribute_Device); - if ((findData->mStat.st_mode & S_IRUSR) == 0) - flags = (BfpFileAttributes)(flags | BfpFileAttribute_ReadOnly); - return flags; -} - -BFP_EXPORT void BFP_CALLTYPE BfpFindFileData_Release(BfpFindFileData* findData) -{ - delete findData; -} - -BFP_EXPORT int BFP_CALLTYPE BfpStack_CaptureBackTrace(int framesToSkip, intptr* outFrames, int wantFrameCount) -{ - // - return 0; -} - -BFP_EXPORT void BFP_CALLTYPE BfpOutput_DebugString(const char* str) -{ - fputs(str, stdout); - fflush(stdout); -} - -////////////////////////////////////////////////////////////////////////// - -void Beefy::BFFatalError(const StringImpl& message, const StringImpl& file, int line) -{ - String error; - error += "ERROR: "; - error += message; - error += " in "; - error += file; - error += StrFormat(" line %d", line); - BfpSystem_FatalError(error.c_str(), "FATAL ERROR"); -} +#include "../posix/PosixCommon.cpp" diff --git a/BeefySysLib/platform/osx/BFPlatform.h b/BeefySysLib/platform/osx/BFPlatform.h index acc558d0b..1bf5d19c1 100644 --- a/BeefySysLib/platform/osx/BFPlatform.h +++ b/BeefySysLib/platform/osx/BFPlatform.h @@ -6,6 +6,8 @@ #include #define BF_PLATFORM_MACOS +#define BF_PLATFORM_POSIX +#define BF_PLATFORM_DARWIN #define BF_PLATFORM_NAME "BF_PLATFORM_MACOS" #define BF_IMPORT extern "C" diff --git a/BeefySysLib/platform/posix/PosixCommon.cpp b/BeefySysLib/platform/posix/PosixCommon.cpp new file mode 100644 index 000000000..e2f80d0da --- /dev/null +++ b/BeefySysLib/platform/posix/PosixCommon.cpp @@ -0,0 +1,2341 @@ +#include "Common.h" +#include "BFPlatform.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../PlatformInterface.h" +#include "../PlatformHelper.h" +#include "../util/CritSect.h" +#include "../util/Dictionary.h" +#include "../util/Hash.h" +#ifdef BFP_HAS_EXECINFO +#include +#endif + +#ifdef BFP_HAS_BACKTRACE +#include "backtrace.h" +#include "backtrace-supported.h" +#endif +#include "../third_party/stb/stb_sprintf.h" +#include +#include + +#ifndef BFP_PRINTF +#define BFP_PRINTF(...) printf (__VA_ARGS__) +#define BFP_ERRPRINTF(...) fprintf (stderr, __VA_ARGS__) +#endif + +USING_NS_BF; + +struct BfpPipeInfo +{ + String mPipePath; + int mWriteHandle; +}; + +struct BfpFile +{ + BfpPipeInfo* mPipeInfo; + int mHandle; + bool mNonBlocking; + bool mAllowTimeout; + bool mIsStd; + + BfpFile() + { + mPipeInfo = NULL; + mHandle = -1; + mNonBlocking = false; + mAllowTimeout = false; + mIsStd = false; + } + + BfpFile(int handle) + { + mPipeInfo = NULL; + mHandle = handle; + mNonBlocking = false; + mAllowTimeout = false; + mIsStd = false; + } + + ~BfpFile() + { + delete mPipeInfo; + } +}; + +BfpTimeStamp BfpToTimeStamp(const timespec& ts) +{ + return (int64)(ts.tv_sec * 10000000) + (int64)(ts.tv_nsec / 100) + 116444736000000000; +} + +int gBFPlatformLastError = 0; + +uint32 Beefy::BFTickCount() +{ + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now)) + return 0; + return (uint32)((uint64)now.tv_sec * 1000.0 + (uint64)now.tv_nsec / 1000000); +} + +int64 Beefy::EndianSwap(int64 val) +{ + return __builtin_bswap64(val); +} + +/*int* GetStdHandle(int32 handleId) +{ + if (handleId == STD_INPUT_HANDLE) + return (int*)STDIN_FILENO; + if (handleId == STD_OUTPUT_HANDLE) + return (int*)STDOUT_FILENO; + return (int*)STDERR_FILENO; +}*/ + +/*int32 GetFileType(HANDLE fileHandle) +{ + if (isatty(file->mHandleHandle)) + return FILE_TYPE_CHAR; + return FILE_TYPE_DISK; +}*/ + +/*bool WriteFile(HANDLE hFile, void* lpBuffer, uint32 nNumberOfBytesToWrite, uint32* lpNumberOfBytesWritten, OVERLAPPED* lpOverlapped) +{ +#ifdef BF_PLATFORM_IOS + int logType = -1; + if (hFile == (int*)STDOUT_FILENO) + logType = LOG_WARNING; + else if (hFile == (int*)STDERR_FILENO) + logType = LOG_ERR; + + if (logType != -1) + { + static std::string strOut; + strOut.resize(nNumberOfBytesToWrite); + memcpy(&strOut[0], lpBuffer, nNumberOfBytesToWrite); + if ((strOut[0] != '\r') && (strOut[0] != '\n')) + syslog(LOG_WARNING, "%s", strOut.c_str()); + } +#endif + + int writeCount = (int)::write((int)(intptr)hFile, lpBuffer, nNumberOfBytesToWrite); + if (writeCount == -1) + { + //TODO: set gBFPlatformLastError + lpNumberOfBytesWritten = 0; + return false; + } + + *lpNumberOfBytesWritten = (uint32)writeCount; + return true; +}*/ + +int64 Beefy::GetFileTimeWrite(const StringImpl& path) +{ + struct stat statbuf = {0}; + int result = stat(path.c_str(), &statbuf); + if (result == -1) + return 0; + + //int64 fileTime = 0; + //BFSystemTimeToFileTime(statbuf.st_mtime, 0, &fileTime); + return statbuf.st_mtime; +} + +/*DWORD GetTimeZoneInformation(TIME_ZONE_INFORMATION* lpTimeZoneInformation) +{ + std::wstring tzName0 = Beefy::UTF8Decode(tzname[0]); + std::wstring tzName1 = Beefy::UTF8Decode(tzname[1]); + + bool isDST = false; + + time_t timeNow; + time(&timeNow); + tm tmNow = *gmtime(&timeNow); + isDST = tmNow.tm_isdst; + + struct tm checkTM; + memset(&checkTM, 0, sizeof(tm)); + checkTM.tm_mday = 1; + checkTM.tm_year = tmNow.tm_year; + time_t checkTime = mktime(&checkTM); + + time_t lastOffset = 0; + time_t minOffset = 0; + time_t maxOffset = 0; + + for (int pass = 0; pass < 2; pass++) + { + int searchDir = 60*60*24; + int thresholdCount = 0; + + while (true) + { + checkTime += searchDir; + + tm checkTM = *gmtime(&checkTime); + + if (checkTM.tm_year != tmNow.tm_year) + break; // No DST + + mktime(&checkTM); + + time_t offset = checkTM.tm_gmtoff; + if (lastOffset != offset) + { + if (thresholdCount == 0) + { + minOffset = offset; + maxOffset = offset; + } + else if (thresholdCount == 3) + { + SYSTEMTIME* sysTimeP = (offset == minOffset) ? + &lpTimeZoneInformation->StandardDate : + &lpTimeZoneInformation->DaylightDate; + + if (offset == minOffset) + tzName0 = Beefy::UTF8Decode(checkTM.tm_zone); + else + tzName1 = Beefy::UTF8Decode(checkTM.tm_zone); + + sysTimeP->wDay = 0; + sysTimeP->wDayOfWeek = 0; + sysTimeP->wYear = checkTM.tm_year + 1900; + sysTimeP->wMonth = checkTM.tm_mon; + sysTimeP->wDay = checkTM.tm_mday + 1; + sysTimeP->wHour = checkTM.tm_hour; + sysTimeP->wMinute = checkTM.tm_min; + sysTimeP->wSecond = checkTM.tm_sec; + sysTimeP->wMilliseconds = 0; + + break; + } + else + { + if (thresholdCount == 1) + searchDir /= -24; + else + searchDir /= -60; + minOffset = std::min(minOffset, offset); + maxOffset = std::max(maxOffset, offset); + } + thresholdCount++; + lastOffset = offset; + } + } + } + + wcsncpy(lpTimeZoneInformation->StandardName, tzName0.c_str(), 32); + wcsncpy(lpTimeZoneInformation->DaylightName, tzName1.c_str(), 32); + + lpTimeZoneInformation->DaylightBias = (int32)maxOffset; + lpTimeZoneInformation->StandardBias = (int32)minOffset; + + if (minOffset == maxOffset) + return 0; + return isDST ? 2 : 1; +}*/ + +bool Beefy::FileExists(const StringImpl& path, String* outActualName) +{ + struct stat statbuf = {0}; + int result = stat(path.c_str(), &statbuf); + if (result != 0) + return false; + return !S_ISDIR(statbuf.st_mode); +} + +bool Beefy::DirectoryExists(const StringImpl& path, String* outActualName) +{ + struct stat statbuf = {0}; + int result = stat(path.c_str(), &statbuf); + if (result != 0) + return false; + return S_ISDIR(statbuf.st_mode); +} + +uint64 Beefy::BFGetTickCountMicro() +{ + struct timespec now; + if (clock_gettime(CLOCK_MONOTONIC, &now)) + return 0; + return ((uint64)now.tv_sec * 1000000.0 + (uint64)now.tv_nsec / 1000); +} + +uint64 Beefy::BFGetTickCountMicroFast() +{ + return BFGetTickCountMicro(); +} + +/* +int64 abs(int64 val) +{ + return llabs(val); +} +*/ +void mkdir(const char* path) +{ + mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); +} + +typedef void(*CrashInfoFunc)(); + +static CritSect gSysCritSect; +static String gCrashInfo; +static Array gCrashInfoFuncs; + +#ifdef BFP_HAS_BACKTRACE + +struct bt_ctx { + struct backtrace_state *state; + int error; +}; + +static void error_callback(void *data, const char *msg, int errnum) +{ + struct bt_ctx *ctx = (bt_ctx*)data; + BFP_ERRPRINTF("ERROR: %s (%d)", msg, errnum); + ctx->error = 1; +} + +static void syminfo_callback (void *data, uintptr_t pc, const char *symname, uintptr_t symval, uintptr_t symsize) +{ + char str[4096]; + if (symname) + stbsp_snprintf(str, 4096, "%@ %s\n", pc, symname); + else + stbsp_snprintf(str, 4096, "%@\n", pc); + BFP_ERRPRINTF("%s", str); +} + +static int full_callback(void *data, uintptr_t pc, const char* filename, int lineno, const char* function) +{ + struct bt_ctx *ctx = (bt_ctx*)data; + if (function) + { + int status = -1; + char* demangledName = abi::__cxa_demangle(function, NULL, NULL, &status ); + const char* showName = (demangledName != NULL) ? demangledName : function; + + char str[4096]; + stbsp_snprintf(str, 4096, "%@ %s %s:%d\n", pc, showName, filename?filename:"??", lineno); + BFP_ERRPRINTF("%s", str); + + if (demangledName != NULL) + free(demangledName); + } + else + backtrace_syminfo (ctx->state, pc, syminfo_callback, error_callback, data); + return 0; +} + +static int simple_callback(void *data, uintptr_t pc) +{ + struct bt_ctx *ctx = (bt_ctx*)data; + backtrace_pcinfo(ctx->state, pc, full_callback, error_callback, data); + return 0; +} + +static inline void bt(struct backtrace_state *state) +{ + struct bt_ctx ctx = {state, 0}; + //backtrace_print(state, 0, stdout); + backtrace_simple(state, 2, simple_callback, error_callback, &ctx); +} + +#endif + +typedef void(*CrashInfoFunc)(); + +static String gCmdLine; +static String gExePath; + +typedef struct _Unwind_Context _Unwind_Context; // opaque + +typedef enum { + _URC_NO_REASON = 0, + _URC_OK = 0, + _URC_FOREIGN_EXCEPTION_CAUGHT = 1, + _URC_FATAL_PHASE2_ERROR = 2, + _URC_FATAL_PHASE1_ERROR = 3, + _URC_NORMAL_STOP = 4, + _URC_END_OF_STACK = 5, + _URC_HANDLER_FOUND = 6, + _URC_INSTALL_CONTEXT = 7, + _URC_CONTINUE_UNWIND = 8, + _URC_FAILURE = 9 +} _Unwind_Reason_Code; + +typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *, void *); +extern "C" _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn, void *); +extern "C" uintptr_t _Unwind_GetIP(struct _Unwind_Context *context); + +static String gUnwindExecStr; +static int gUnwindIdx = 0; + +static _Unwind_Reason_Code UnwindHandler(struct _Unwind_Context* context, void* ref) +{ + gUnwindIdx++; + if (gUnwindIdx < 2) + return _URC_NO_REASON; + + void* addr = (void*)_Unwind_GetIP(context); + +#if BFP_HAS_ATOS + gUnwindExecStr += StrFormat(" %p", addr); +#else + Dl_info info; + if (dladdr(addr, &info) && info.dli_sname) + { + BFP_ERRPRINTF("0x%p %s\n", addr, info.dli_sname); + } +#endif + return _URC_NO_REASON; +} + +static bool FancyBacktrace() +{ + gUnwindExecStr += StrFormat("atos -p %d", getpid()); + _Unwind_Backtrace(&UnwindHandler, NULL); +#if BFP_HAS_ATOS + return system(gUnwindExecStr.c_str()) == 0; +#else + return true; +#endif +} + +static void Crashed() +{ + // + { + AutoCrit autoCrit(gSysCritSect); + + String debugDump; + + debugDump += "**** FATAL APPLICATION ERROR ****\n"; + + for (auto func : gCrashInfoFuncs) + func(); + + if (!gCrashInfo.IsEmpty()) + { + debugDump += gCrashInfo; + debugDump += "\n"; + } + + BFP_ERRPRINTF("%s", debugDump.c_str()); + } + + if (!FancyBacktrace()) + { +#ifdef BFP_HAS_EXECINFO + void* array[64]; + size_t size; + char** strings; + size_t i; + + size = backtrace(array, 64); + strings = backtrace_symbols(array, size); + + for (i = 0; i < size; i++) + BFP_ERRPRINTF("%s\n", strings[i]); + + free(strings); +#endif + } + + exit(1); +} + +static void SigHandler(int sig) +{ + //printf("SigHandler paused...\n"); + + const char* sigName = NULL; + switch (sig) + { + case SIGFPE: + sigName = "SIGFPE"; + break; + case SIGSEGV: + sigName = "SIGSEGV"; + break; + case SIGABRT: + sigName = "SIGABRT"; + break; + case SIGILL: + sigName = "SIGILL"; + break; + } + + if (sigName != NULL) + gCrashInfo += StrFormat("Signal: %s\n", sigName); + else + gCrashInfo += StrFormat("Signal: %d\n", sig); + Crashed(); +} + +BFP_EXPORT void BFP_CALLTYPE BfpSystem_Init(int version, BfpSystemInitFlags flags) +{ + if (version != BFP_VERSION) + { + BfpSystem_FatalError(StrFormat("Bfp build version '%d' does not match requested version '%d'", BFP_VERSION, version).c_str(), "BFP FATAL ERROR"); + } + + signal(SIGSEGV, SigHandler); + signal(SIGFPE, SigHandler); + signal(SIGABRT, SigHandler); +} + +BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCommandLine(int argc, char** argv) +{ + char* relPath = argv[0]; + + char* cwd = getcwd(NULL, 0); + gExePath = GetAbsPath(relPath, cwd); + free(cwd); + + for (int i = 0; i < argc; i++) + { + if (i != 0) + gCmdLine.Append(' '); + + String arg = argv[i]; + if ((arg.Contains(' ')) || (arg.Contains('\"'))) + { + arg.Replace("\"", "\\\""); + gCmdLine.Append("\""); + gCmdLine.Append(arg); + gCmdLine.Append("\""); + } + else + gCmdLine.Append(arg); + } +} + + +BFP_EXPORT void BFP_CALLTYPE BfpSystem_SetCrashReportKind(BfpCrashReportKind crashReportKind) +{ + +} + +BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfoFunc(BfpCrashInfoFunc crashInfoFunc) +{ + AutoCrit autoCrit(gSysCritSect); + gCrashInfoFuncs.Add(crashInfoFunc); +} + +BFP_EXPORT void BFP_CALLTYPE BfpSystem_AddCrashInfo(const char* str) // Can do at any time, or during CrashInfoFunc callbacks +{ + AutoCrit autoCrit(gSysCritSect); + gCrashInfo.Append(str); +} + +void BfpSystem_Shutdown() +{ + +} + +BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_TickCount() +{ + return Beefy::BFTickCount(); +} + +BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpSystem_GetTimeStamp() +{ + struct timeval tv; + BfpTimeStamp result = 11644473600LL; + gettimeofday(&tv, NULL); + result += tv.tv_sec; + result *= 10000000LL; + result += tv.tv_usec * 10; + return result; +} + +BFP_EXPORT uint16 BFP_CALLTYPE BfpSystem_EndianSwap16(uint16 val) +{ + return __builtin_bswap16(val); +} + +BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_EndianSwap32(uint32 val) +{ + return __builtin_bswap32(val); +} + +BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_EndianSwap64(uint64 val) +{ + return __builtin_bswap64(val); +} + +BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedExchange32(uint32* ptr, uint32 val) +{ + // __sync_lock_test_and_set only has Acquire semantics, so we need a __sync_synchronize to enforce a full barrier + uint32 prevVal = __sync_lock_test_and_set(ptr, val); + __sync_synchronize(); + return prevVal; +} + +BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedExchange64(uint64* ptr, uint64 val) +{ + // __sync_lock_test_and_set only has Acquire semantics, so we need a __sync_synchronize to enforce a full barrier + uint64 prevVal = __sync_lock_test_and_set(ptr, val); + __sync_synchronize(); + return prevVal; +} + +BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedExchangeAdd32(uint32* ptr, uint32 val) +{ + return __sync_fetch_and_add(ptr, val); +} + +BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedExchangeAdd64(uint64* ptr, uint64 val) +{ + return __sync_fetch_and_add(ptr, val); +} + +BFP_EXPORT uint32 BFP_CALLTYPE BfpSystem_InterlockedCompareExchange32(uint32* ptr, uint32 oldVal, uint32 newVal) +{ + return __sync_val_compare_and_swap(ptr, oldVal, newVal); +} + +BFP_EXPORT uint64 BFP_CALLTYPE BfpSystem_InterlockedCompareExchange64(uint64* ptr, uint64 oldVal, uint64 newVal) +{ + return __sync_val_compare_and_swap(ptr, oldVal, newVal); +} + +BFP_EXPORT void BFP_CALLTYPE BfpSystem_FatalError(const char* error, const char* title) +{ + BFP_ERRPRINTF("%s\n", error); + fflush(stderr); + Crashed(); +} + +BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetCommandLine(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) +{ + TryStringOut(gCmdLine, outStr, inOutStrSize, (BfpResult*)outResult); +} + +BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetExecutablePath(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) +{ +#ifdef BF_PLATFORM_DARWIN + if (gExePath.IsEmpty()) + { + char path[4096]; + uint32_t size = sizeof(path); + if (_NSGetExecutablePath(path, &size) == 0) + gExePath = path; + + // When when running with a './file', we end up with an annoying '/./' in our path + gExePath.Replace("/./", "/"); + } +#endif + + TryStringOut(gExePath, outStr, inOutStrSize, (BfpResult*)outResult); +} + +extern char **environ; + +BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetEnvironmentStrings(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) +{ + String env; + + char** envPtr = environ; + while (true) + { + char* envStr = *envPtr; + env.Append(envStr, strlen(envStr) + 1); + ++envPtr; + } + + TryStringOut(env, outStr, inOutStrSize, (BfpResult*)outResult); +} + +BFP_EXPORT int BFP_CALLTYPE BfpSystem_GetNumLogicalCPUs(BfpSystemResult* outResult) +{ +#ifdef BF_PLATFORM_ANDROID + //TODO: Handle this + OUTRESULT(BfpSystemResult_Ok); + return 1; +#elif defined BF_PLATFORM_DARWIN + OUTRESULT(BfpSystemResult_Ok); + int count = 1; + size_t count_len = sizeof(count); + sysctlbyname("hw.logicalcpu", &count, &count_len, NULL, 0); + return count; +#else + OUTRESULT(BfpSystemResult_Ok); + return get_nprocs_conf(); +#endif +} + +BFP_EXPORT int64 BFP_CALLTYPE BfpSystem_GetCPUTick() +{ + return 10000000; +} + +BFP_EXPORT int64 BFP_CALLTYPE BfpSystem_GetCPUTickFreq() +{ + struct timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return (now.tv_sec * 10000000LL) + now.tv_nsec / 100; +} + +BFP_EXPORT void BFP_CALLTYPE BfpSystem_CreateGUID(BfpGUID* outGuid) +{ +// uuid_t guid; +// uuid_generate(guid); +// BfpGUID bfpGuid; +// memcpy(&bfpGuid, guid, 16); +// return bfpGuid; + + uint8* ptr = (uint8*)outGuid; + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution dis(0, 255); + for (int i = 0; i < 16; i++) + ptr[i] = dis(gen); + + // variant must be 10xxxxxx + ptr[8] &= 0xBF; + ptr[8] |= 0x80; + + // version must be 0100xxxx + ptr[6] &= 0x4F; + ptr[6] |= 0x40; +} + +BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetComputerName(char* outStr, int* inOutStrSize, BfpSystemResult* outResult) +{ + char hostName[1024]; + gethostname(hostName, 1024); + TryStringOut(hostName, outStr, inOutStrSize, (BfpResult*)outResult); +} + +// BfpProcess + +BFP_EXPORT intptr BFP_CALLTYPE BfpProcess_GetCurrentId() +{ + return getpid(); +} + +BFP_EXPORT bool BFP_CALLTYPE BfpProcess_IsRemoteMachine(const char* machineName) +{ + return false; +} + +BFP_EXPORT BfpProcess* BFP_CALLTYPE BfpProcess_GetById(const char* machineName, int processId, BfpProcessResult* outResult) +{ + NOT_IMPL; + return NULL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpProcess_Enumerate(const char* machineName, BfpProcess** outProcesses, int* inOutProcessesSize, BfpProcessResult* outResult) +{ + NOT_IMPL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpProcess_Release(BfpProcess* process) +{ + NOT_IMPL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpProcess_GetMainWindowTitle(BfpProcess* process, char* outTitle, int* inOutTitleSize, BfpProcessResult* outResult) +{ + NOT_IMPL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpProcess_GetProcessName(BfpProcess* process, char* outName, int* inOutNameSize, BfpProcessResult* outResult) +{ + NOT_IMPL; +} + +BFP_EXPORT int BFP_CALLTYPE BfpProcess_GetProcessId(BfpProcess* process) +{ + NOT_IMPL; + return 0; +} + +// BfpSpawn + +struct BfpSpawn +{ + int mPid; + bool mExited; + int mStatus; + int mStdInFD; + int mStdOutFD; + int mStdErrFD; +}; + +BFP_EXPORT BfpSpawn* BFP_CALLTYPE BfpSpawn_Create(const char* inTargetPath, const char* args, const char* workingDir, const char* env, BfpSpawnFlags flags, BfpSpawnResult* outResult) +{ + Beefy::Array stringViews; + + //printf("Executing: %s %s %x\n", inTargetPath, args, flags); + + if ((workingDir != NULL) && (workingDir[0] != 0)) + { + if (chdir(workingDir) != 0) + { + //printf("CHDIR failed %s\n", workingDir); + OUTRESULT(BfpSpawnResult_UnknownError); + return NULL; + } + } + + String newArgs; + String tempFileName; + + if ((flags & BfpSpawnFlag_UseArgsFile) != 0) + { + char tempFileNameStr[256]; + int size = 256; + BfpFileResult fileResult; + BfpFile_GetTempFileName(tempFileNameStr, &size, &fileResult); + if (fileResult == BfpFileResult_Ok) + { + tempFileName = tempFileNameStr; + + BfpFileResult fileResult; + BfpFile* file = BfpFile_Create(tempFileNameStr, BfpFileCreateKind_CreateAlways, BfpFileCreateFlag_Write, BfpFileAttribute_Normal, &fileResult); + if (file == NULL) + { + OUTRESULT(BfpSpawnResult_TempFileError); + return NULL; + } + + if ((flags & BfpSpawnFlag_UseArgsFile_Native) != 0) + { + UTF16String wStr = UTF8Decode(args); + + if ((flags & BfpSpawnFlag_UseArgsFile_BOM) != 0) + { + uint8 bom[2] = { 0xFF, 0xFE }; + BfpFile_Write(file, bom, 2, -1, NULL); + } + + BfpFile_Write(file, wStr.c_str(), wStr.length() * 2, -1, NULL); + } + else + BfpFile_Write(file, args, strlen(args), -1, NULL); + BfpFile_Release(file); + + newArgs.Append("@"); + newArgs.Append(tempFileName); + if (newArgs.Contains(' ')) + { + newArgs.Insert(0, '\"'); + newArgs.Append('\"'); + } + + args = newArgs.c_str(); + } + } + + int32 firstCharIdx = -1; + bool inQuote = false; + + String targetPath = inTargetPath; + String verb; + if ((flags & BfpSpawnFlag_UseShellExecute) != 0) + { + String target = targetPath; + int barPos = (int)target.IndexOf('|'); + if (barPos != -1) + { + verb = targetPath.Substring(barPos + 1); + targetPath.RemoveToEnd(barPos); + } + } + + int32 i = 0; + for ( ; true; i++) + { + char c = args[i]; + if (c == '\0') + break; + if ((c == ' ') && (!inQuote)) + { + if (firstCharIdx != -1) + { + stringViews.Add(Beefy::StringView(args, firstCharIdx, i - firstCharIdx)); + firstCharIdx = -1; + } + } + else + { + if (firstCharIdx == -1) + firstCharIdx = i; + if (c == '"') + inQuote = !inQuote; + else if ((inQuote) && (c == '\\')) + { + c = args[i + 1]; + if (c == '"') + i++; + } + } + } + if (firstCharIdx != -1) + stringViews.Add(Beefy::StringView(args, firstCharIdx, i - firstCharIdx)); + + Beefy::Array argvArr; + + if ((flags & BfpSpawnFlag_ArgsIncludesTarget) == 0) + argvArr.Add(strdup(targetPath.c_str())); + + for (int32 i = 0; i < (int32)stringViews.size(); i++) + { + Beefy::StringView stringView = stringViews[i]; + char* str = NULL; + for (int32 pass = 0; pass < 2; pass++) + { + char* strPtr = str; + + int32 strPos = 0; + for (int32 char8Idx = 0; char8Idx < stringView.mLength; char8Idx++) + { + char c = stringView.mPtr[char8Idx]; + if (c == '"') + inQuote = !inQuote; + else + { + if ((inQuote) && (c == '\\') && (char8Idx < stringView.mLength - 1)) + { + char nextC = stringView.mPtr[char8Idx + 1]; + if (nextC == '"') + { + c = nextC; + char8Idx++; + } + } + if (strPtr != NULL) + *(strPtr++) = c; + strPos++; + } + } + if (pass == 0) + str = (char*)malloc(strPos + 1); + else + *(strPtr++) = 0; + } + + argvArr.Add(str); + } + argvArr.Add(NULL); + + char** argv = NULL; + + //pid_t pid = 0; + //int status = posix_spawn(&pid, targetPath, NULL, NULL, &argvArr[0], environ); + + Beefy::Array envArr; + if (env != NULL) + { + char* envPtr = (char*)env; + while (true) + { + if (*envPtr == 0) + break; + + envArr.Add(envPtr); + envPtr += strlen(envPtr) + 1; + } + } + envArr.Add(NULL); + + int stdInFD[2]; + int stdOutFD[2]; + int stdErrFD[2]; + + bool failed = false; + if ((flags & BfpSpawnFlag_RedirectStdInput) != 0) + if (pipe(stdInFD) != 0) + failed = true; + if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0) + if (pipe(stdOutFD) != 0) + failed = true; + if ((flags & BfpSpawnFlag_RedirectStdError) != 0) + if (pipe(stdErrFD) != 0) + failed = true; + if (failed) + { + //printf("Pipe failed\n"); + OUTRESULT(BfpSpawnResult_UnknownError); + return NULL; + } + + BfpSpawn* spawn; + pid_t pid = fork(); + if (pid == -1) // Error + { + OUTRESULT(BfpSpawnResult_UnknownError); + return NULL; + } + else if (pid == 0) // Child + { + if ((flags & BfpSpawnFlag_RedirectStdInput) != 0) + while ((dup2(stdInFD[0], STDIN_FILENO) == -1) && (errno == EINTR)) {} + if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0) + while ((dup2(stdOutFD[1], STDOUT_FILENO) == -1) && (errno == EINTR)) {} + if ((flags & BfpSpawnFlag_RedirectStdError) != 0) + while ((dup2(stdErrFD[1], STDERR_FILENO) == -1) && (errno == EINTR)) {} + + // If successful then this shouldn't return at all: + int result; + + if (env != NULL) + result = execve(targetPath.c_str(), (char* const*)&argvArr[0], (char* const*)&envArr[0]); + else + result = execv(targetPath.c_str(), (char* const*)&argvArr[0]); + + BFP_ERRPRINTF("Couldn't execute %s\n", targetPath.c_str()); + + exit(-1); + } + else // Parent + { + spawn = new BfpSpawn(); + + if ((flags & BfpSpawnFlag_RedirectStdInput) != 0) + { + spawn->mStdInFD = stdInFD[1]; + close(stdInFD[0]); + } + else + spawn->mStdInFD = 0; + + if ((flags & BfpSpawnFlag_RedirectStdOutput) != 0) + { + spawn->mStdOutFD = stdOutFD[0]; + close(stdOutFD[1]); + } + else + spawn->mStdOutFD = 0; + + if ((flags & BfpSpawnFlag_RedirectStdError) != 0) + { + spawn->mStdErrFD = stdErrFD[0]; + close(stdErrFD[1]); + } + else + spawn->mStdErrFD = 0; + } + + for (auto val : argvArr) + free(val); + + //printf("Spawn pid:%d status:%d\n", pid, status); + spawn->mPid = pid; + spawn->mExited = false; + spawn->mStatus = 0; + + return spawn; +} + +void BfpSpawn_Release(BfpSpawn* spawn) +{ + // We don't support 'detaching' currently- this can create zombie processes since we + // don't have a reaper strategy + BfpSpawn_WaitFor(spawn, -1, NULL, NULL); + + delete spawn; +} + +BFP_EXPORT void BFP_CALLTYPE BfpSpawn_GetStdHandles(BfpSpawn* spawn, BfpFile** outStdIn, BfpFile** outStdOut, BfpFile** outStdErr) +{ + if (outStdIn != NULL) + { + *outStdIn = new BfpFile(spawn->mStdInFD); + spawn->mStdInFD = 0; + } + + if (outStdOut != NULL) + { + *outStdOut = new BfpFile(spawn->mStdOutFD); + spawn->mStdOutFD = 0; + } + + if (outStdErr != NULL) + { + *outStdErr = new BfpFile(spawn->mStdErrFD); + spawn->mStdErrFD = 0; + } +} + +bool BfpSpawn_WaitFor(BfpSpawn* spawn, int waitMS, int* outExitCode, BfpSpawnResult* outResult) +{ + OUTRESULT(BfpSpawnResult_Ok); + if (!spawn->mExited) + { + int flags = 0; + if (waitMS != -1) + { + flags = WNOHANG; + } + //TODO: Implement values other than 0 or -1 for waitMS? + + pid_t result = waitpid(spawn->mPid, &spawn->mStatus, flags); + if (result != spawn->mPid) + return false; + + spawn->mExited = true; + } + + if (!WIFEXITED(spawn->mStatus) && !WIFSIGNALED(spawn->mStatus)) + return false; + + if (outExitCode != NULL) + *outExitCode = WEXITSTATUS(spawn->mStatus); + return true; +} + +// BfpFileWatcher + +BFP_EXPORT BfpFileWatcher* BFP_CALLTYPE BfpFileWatcher_WatchDirectory(const char* path, BfpDirectoryChangeFunc callback, BfpFileWatcherFlags flags, void* userData, BfpFileResult* outResult) +{ + NOT_IMPL; + return NULL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpFileWatcher_Release(BfpFileWatcher* fileWatcher) +{ + NOT_IMPL; +} + +// BfpThread + +struct BfpThread +{ + bool mPThreadReleased; + BfpThreadStartProc mStartProc; + void* mThreadParam; +#ifndef BFP_HAS_PTHREAD_TIMEDJOIN_NP + BfpEvent* mDoneEvent; +#endif + + pthread_t mPThread; + int mRefCount; + int mPriority; + + BfpThread() + { + } + + void Release() + { + int refCount = __sync_fetch_and_sub(&mRefCount, 1) - 1; + if (refCount == 0) + delete this; + } +}; + +struct BfpThreadInfo +{ + intptr mStackBase; + int mStackLimit; +}; + +static __thread BfpThread* gCurrentThread; +static __thread BfpThreadInfo gCurrentThreadInfo; + +void* ThreadFunc(void* threadParam) +{ + BfpThread* thread = (BfpThread*)threadParam; + gCurrentThread = thread; + thread->mStartProc(thread->mThreadParam); +#ifndef BFP_HAS_PTHREAD_TIMEDJOIN_NP + BfpEvent_Set(thread->mDoneEvent, true); +#endif + thread->Release(); + return NULL; +} + +BFP_EXPORT BfpThread* BFP_CALLTYPE BfpThread_Create(BfpThreadStartProc startProc, void* threadParam, intptr stackSize, BfpThreadCreateFlags flags, BfpThreadId* outThreadId) +{ + BfpThread* thread = new BfpThread(); + thread->mPThreadReleased = false; + thread->mStartProc = startProc; + thread->mThreadParam = threadParam; + thread->mRefCount = 2; + thread->mPriority = 0; +#ifndef BFP_HAS_PTHREAD_TIMEDJOIN_NP + thread->mDoneEvent = BfpEvent_Create(BfpEventFlag_None); +#endif + + BF_ASSERT(sizeof(pthread_t) <= sizeof(void*)); + pthread_attr_t params; + pthread_attr_init(¶ms); + pthread_attr_setstacksize(¶ms, stackSize); + //pthread_attr_setdetachstate(¶ms,PTHREAD_CREATE_DETACHED); + + pthread_create(&thread->mPThread, ¶ms, ThreadFunc, (void*)thread); + + pthread_attr_destroy(¶ms); + + if (outThreadId != NULL) + *outThreadId = (BfpThreadId)thread->mPThread; + + return thread; +} + +#define FIXTHREAD() \ + pthread_t pt; \ + if (((intptr)thread & 1) != 0) \ + { \ + pt = (pthread_t)((intptr)thread & ~3); \ + thread = NULL; \ + } else \ + pt = thread->mPThread + +BFP_EXPORT void BFP_CALLTYPE BfpThread_Release(BfpThread* thread) +{ + FIXTHREAD(); + if (thread == NULL) + return; + +#ifndef BFP_HAS_PTHREAD_TIMEDJOIN_NP + BfpEvent_Release(thread->mDoneEvent); +#endif + if (!thread->mPThreadReleased) + { + pthread_detach(thread->mPThread); + thread->mPThreadReleased = true; + } + thread->Release(); +} + +BFP_EXPORT void BFP_CALLTYPE BfpThread_SetName(BfpThread* thread, const char* name, BfpThreadResult* outResult) +{ + OUTRESULT(BfpThreadResult_Ok); +} + +BFP_EXPORT void BFP_CALLTYPE BfpThread_GetName(BfpThread* thread, char* outName, int* inOutNameSize, BfpThreadResult* outResult) +{ + String str = ""; + TryStringOut(str, outName, inOutNameSize, (BfpResult*)outResult); +} + +BFP_EXPORT BfpThread* BFP_CALLTYPE BfpThread_GetCurrent() +{ + if (gCurrentThread == NULL) + { + // Not a "true" BfpThread, this is either the main thread or a thread we didn't create + return (BfpThread*)((intptr)pthread_self() | 1); + } + return gCurrentThread; +} + +BFP_EXPORT BfpThreadId BFP_CALLTYPE BfpThread_GetCurrentId() +{ + if (gCurrentThread == NULL) + { + return (BfpThreadId)((intptr)pthread_self()); + } + return (BfpThreadId)gCurrentThread->mPThread; +} + +BFP_EXPORT bool BFP_CALLTYPE BfpThread_WaitFor(BfpThread* thread, int waitMS) +{ + FIXTHREAD(); + + if (waitMS == -1) + { + pthread_join(pt, NULL); + thread->mPThreadReleased = true; + return true; + } + +#ifdef BFP_HAS_PTHREAD_TIMEDJOIN_NP + struct timespec waitTime; + waitTime.tv_sec = waitMS / 1000; + waitTime.tv_nsec = (waitMS % 1000) * 1000000; + int result = pthread_timedjoin_np(pt, NULL, &waitTime); + if (result == 0) + { + if (thread != NULL) + thread->mPThreadReleased = true; + return true; + } + return false; +#else + if (thread == NULL) + BF_FATAL("Invalid thread with non-infinite wait"); + return BfpEvent_WaitFor(thread->mDoneEvent, waitMS); +#endif +} + +BFP_EXPORT void BFP_CALLTYPE BfpSpawn_Kill(BfpSpawn* spawn, int exitCode, BfpKillFlags killFlags, BfpSpawnResult* outResult) +{ + //TODO: Implement + OUTRESULT(BfpSpawnResult_UnknownError); +} + +BFP_EXPORT BfpThreadPriority BFP_CALLTYPE BfpThread_GetPriority(BfpThread* thread, BfpThreadResult* outResult) +{ + FIXTHREAD(); + + OUTRESULT(BfpThreadResult_Ok); + if (thread == NULL) + return (BfpThreadPriority)0; + + return (BfpThreadPriority)thread->mPriority; +} + +BFP_EXPORT void BFP_CALLTYPE BfpThread_SetPriority(BfpThread* thread, BfpThreadPriority threadPriority, BfpThreadResult* outResult) +{ + // In effect, we have two 'nice' settings: 0 (normal) or 10 (low) + // High-priority settings just don't do anything + //pid_t tid = syscall(SYS_gettid); + //int ret = setpriority(PRIO_PROCESS, tid, -std::min(nPriority, 0) * 10); + OUTRESULT(BfpThreadResult_Ok); +} + +BFP_EXPORT void BFP_CALLTYPE BfpThread_Suspend(BfpThread* thread, BfpThreadResult* outResult) +{ + NOT_IMPL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpThread_Resume(BfpThread* thread, BfpThreadResult* outResult) +{ + NOT_IMPL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpThread_GetIntRegisters(BfpThread* thread, intptr* outStackPtr, intptr* outIntRegs, int* inOutIntRegCount, BfpThreadResult* outResult) +{ + NOT_IMPL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpThread_GetStackInfo(BfpThread* thread, intptr* outStackBase, int* outStackLimit, BfpThreadResult* outResult) +{ +#ifdef BFP_HAS_PTHREAD_GETATTR_NP + if (gCurrentThreadInfo.mStackBase == 0) + { + void* stackBase = 0; + size_t stackLimit = 0; + + pthread_attr_t attr; + pthread_getattr_np(pthread_self(), &attr); + pthread_attr_getstack(&attr, &stackBase, &stackLimit); + + gCurrentThreadInfo.mStackBase = (intptr)stackBase + stackLimit; + gCurrentThreadInfo.mStackLimit = (int)stackLimit; + pthread_attr_destroy(&attr); + } + + *outStackBase = gCurrentThreadInfo.mStackBase; + *outStackLimit = gCurrentThreadInfo.mStackLimit; + + OUTRESULT(BfpThreadResult_Ok); +#else + OUTRESULT(BfpThreadResult_UnknownError); +#endif +} + +BFP_EXPORT void BFP_CALLTYPE BfpThread_Sleep(int sleepMS) +{ + usleep(sleepMS * 1000); +} + +BFP_EXPORT bool BFP_CALLTYPE BfpThread_Yield() +{ + return sched_yield() == 0; +} + +struct BfpCritSect +{ + pthread_mutex_t mPMutex; +}; + +BFP_EXPORT BfpCritSect* BFP_CALLTYPE BfpCritSect_Create() +{ + BfpCritSect* critSect = new BfpCritSect(); + + pthread_mutexattr_t attributes; + pthread_mutexattr_init(&attributes); + pthread_mutexattr_settype(&attributes, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&critSect->mPMutex, &attributes); + pthread_mutexattr_destroy(&attributes); + + return critSect; +} + +BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Release(BfpCritSect* critSect) +{ + pthread_mutex_destroy(&critSect->mPMutex); +} + +BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Enter(BfpCritSect* critSect) +{ + pthread_mutex_lock(&critSect->mPMutex); +} + +BFP_EXPORT bool BFP_CALLTYPE BfpCritSect_TryEnter(BfpCritSect* critSect, int waitMS) +{ + if (waitMS == -1) + { + BfpCritSect_Enter(critSect); + return true; + } + else if (waitMS == 0) + { + return pthread_mutex_trylock(&critSect->mPMutex) == 0; + } + + uint32 start = Beefy::BFTickCount(); + while ((int)(Beefy::BFTickCount() - start) < waitMS) + { + if (pthread_mutex_trylock(&critSect->mPMutex) == 0) + { + return true; + } + } + return false; +} + +BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Leave(BfpCritSect* critSect) +{ + pthread_mutex_unlock(&critSect->mPMutex); +} + +BFP_EXPORT BfpTLS* BFP_CALLTYPE BfpTLS_Create() +{ + pthread_key_t key = 0; + pthread_key_create(&key, NULL); + return (BfpTLS*)(intptr)key; +} + +BFP_EXPORT void BFP_CALLTYPE BfpTLS_Release(BfpTLS* tls) +{ + pthread_key_delete((pthread_key_t)(intptr)tls); +} + +BFP_EXPORT void BFP_CALLTYPE BfpTLS_SetValue(BfpTLS* tls, void* value) +{ + pthread_setspecific((pthread_key_t)(intptr)tls, value); +} + +BFP_EXPORT void* BFP_CALLTYPE BfpTLS_GetValue(BfpTLS* tls) +{ + return pthread_getspecific((pthread_key_t)(intptr)tls); +} + +struct BfpEvent +{ + pthread_mutex_t mMutex; + pthread_cond_t mCondVariable; + bool mSet; + bool mManualReset; +}; + +BFP_EXPORT BfpEvent* BFP_CALLTYPE BfpEvent_Create(BfpEventFlags flags) +{ + BfpEvent* event = new BfpEvent(); + pthread_mutex_init(&event->mMutex, NULL); + pthread_cond_init(&event->mCondVariable, NULL); + event->mSet = (flags & (BfpEventFlag_InitiallySet_Auto | BfpEventFlag_InitiallySet_Manual)) != 0; + event->mManualReset = (flags & BfpEventFlag_InitiallySet_Manual) != 0; + return event; +} + +BFP_EXPORT void BFP_CALLTYPE BfpEvent_Release(BfpEvent* event) +{ + pthread_cond_destroy(&event->mCondVariable); + pthread_mutex_destroy(&event->mMutex); +} + +BFP_EXPORT void BFP_CALLTYPE BfpEvent_Set(BfpEvent* event, bool requireManualReset) +{ + pthread_mutex_lock(&event->mMutex); + event->mSet = true; + if (requireManualReset) + event->mManualReset = true; + if (event->mManualReset) + pthread_cond_broadcast(&event->mCondVariable); + else + pthread_cond_signal(&event->mCondVariable); + pthread_mutex_unlock(&event->mMutex); +} + +BFP_EXPORT void BFP_CALLTYPE BfpEvent_Reset(BfpEvent* event, BfpEventResult* outResult) +{ + event->mSet = false; + event->mManualReset = false; +} + +BFP_EXPORT bool BFP_CALLTYPE BfpEvent_WaitFor(BfpEvent* event, int waitMS) +{ + int result = pthread_mutex_lock(&event->mMutex); + BF_ASSERT(result == 0); + while (!event->mSet) + { + if (waitMS == -1) + { + pthread_cond_wait(&event->mCondVariable, &event->mMutex); + } + else + { + timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += waitMS / 1000; + ts.tv_nsec += (waitMS % 1000) * 1000000; + + result = pthread_cond_timedwait(&event->mCondVariable, &event->mMutex, &ts); + + if (waitMS == (uint32)-1) + BF_ASSERT(result == 0); + + if (result != 0) + { + // Timeout + pthread_mutex_unlock(&event->mMutex); + return false; + } + } + } + if (!event->mManualReset) + event->mSet = false; + pthread_mutex_unlock(&event->mMutex); + return true; +} + +BFP_EXPORT BfpDynLib* BFP_CALLTYPE BfpDynLib_Load(const char* fileName) +{ + BfpDynLib* mod = NULL; + + static const char* prefixes[] = {NULL, "lib"}; + static const char* suffixes[] = {NULL, ".so", ".dylib"}; + + for (int prefixIdx = 0; prefixIdx < sizeof(prefixes)/sizeof(prefixes[0]); prefixIdx++) + { + for (int suffixIdx = 0; suffixIdx < sizeof(suffixes)/sizeof(suffixes[0]); suffixIdx++) + { + const char* prefix = prefixes[prefixIdx]; + const char* suffix = suffixes[suffixIdx]; + + Beefy::String checkName = fileName; + if (prefix != NULL) + checkName = Beefy::String(prefix) + checkName; + if (suffix != NULL) + { + int dotPos = checkName.LastIndexOf('.'); + if (dotPos != -1) + checkName.RemoveToEnd(dotPos); + checkName += suffix; + } + + mod = (BfpDynLib*)dlopen(checkName.c_str(), RTLD_LAZY); + if (mod != NULL) + return mod; + } + } + + /*mod = (BfpDynLib*)dlopen("/var/Beef/qt-build/Debug/bin/libIDEHelper.so", RTLD_LAZY);; + if (mod == NULL) + { + printf("Err: %s\n", dlerror()); + fflush(stdout); + }*/ + + return NULL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpDynLib_Release(BfpDynLib* lib) +{ + dlclose((void*)lib); +} + +BFP_EXPORT void BFP_CALLTYPE BfpDynLib_GetFilePath(BfpDynLib* lib, char* outPath, int* inOutPathSize, BfpLibResult* outResult) +{ + Beefy::String path; + +#ifdef BFP_HAS_DLINFO + link_map* linkMap = NULL; + dlinfo((void*)lib, RTLD_DI_LINKMAP, &linkMap); + if (linkMap == NULL) + { + OUTRESULT(BfpLibResult_UnknownError); + return; + } + + path = linkMap->l_name; +#else + Dl_info info; + if (dladdr((void*)lib, &info) == 0) + { + OUTRESULT(BfpLibResult_UnknownError); + return; + } + + path = info.dli_fname; +#endif + + TryStringOut(path, outPath, inOutPathSize, (BfpResult*)outResult); +} + +BFP_EXPORT void* BFP_CALLTYPE BfpDynLib_GetProcAddress(BfpDynLib* lib, const char* name) +{ + return dlsym((void*)lib, name); +} + +BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Create(const char* path, BfpFileResult* outResult) +{ + if (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) + { + switch (errno) + { + case EEXIST: + OUTRESULT(BfpFileResult_AlreadyExists); + break; + case ENOENT: + OUTRESULT(BfpFileResult_NotFound); + break; + default: + OUTRESULT(BfpFileResult_UnknownError); + break; + } + } + else + OUTRESULT(BfpFileResult_Ok); +} + +BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Rename(const char* oldName, const char* newName, BfpFileResult* outResult) +{ + NOT_IMPL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpDirectory_Delete(const char* path, BfpFileResult* outResult) +{ + if (rmdir(path) != 0) + { + switch (errno) + { + case ENOENT: + OUTRESULT(BfpFileResult_NotFound); + break; + default: + OUTRESULT(BfpFileResult_UnknownError); + break; + } + } + else + OUTRESULT(BfpFileResult_Ok); +} + +BFP_EXPORT void BFP_CALLTYPE BfpDirectory_GetCurrent(char* outPath, int* inOutPathSize, BfpFileResult* outResult) +{ + char* str = getcwd(NULL, 0); + Beefy::String path = str; + free(str); + TryStringOut(path, outPath, inOutPathSize, (BfpResult*)outResult); +} + +BFP_EXPORT void BFP_CALLTYPE BfpDirectory_SetCurrent(const char* path, BfpFileResult* outResult) +{ + if (chdir(path) != 0) + OUTRESULT(BfpFileResult_NotFound); + else + OUTRESULT(BfpFileResult_Ok); +} + +BFP_EXPORT bool BFP_CALLTYPE BfpDirectory_Exists(const char* path) +{ + struct stat statbuf = {0}; + int result = stat(path, &statbuf); + if (result != 0) + return false; + return S_ISDIR(statbuf.st_mode); +} + +BFP_EXPORT void BFP_CALLTYPE BfpDirectory_GetSysDirectory(BfpSysDirectoryKind sysDirKind, char* outPath, int* inOutPathLen, BfpFileResult* outResult) +{ + String path = "~"; + TryStringOut(path, outPath, inOutPathLen, (BfpResult*)outResult); +} + +BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_Create(const char* inName, BfpFileCreateKind createKind, BfpFileCreateFlags createFlags, BfpFileAttributes createdFileAttrs, BfpFileResult* outResult) +{ + auto _DoCreate = [&](String& name) + { + int flags = 0; + int mode = 0; + int pipePairHandle = -1; + + if ((createFlags & (BfpFileCreateFlag_Read | BfpFileCreateFlag_Write)) == (BfpFileCreateFlag_Read | BfpFileCreateFlag_Write)) + flags |= O_RDWR; + else if ((createFlags & BfpFileCreateFlag_Read) != 0) + flags |= O_RDONLY; + else if ((createFlags & BfpFileCreateFlag_Write) != 0) + flags |= O_WRONLY; + + if ((createFlags & BfpFileCreateFlag_Append) != 0) + flags |= O_APPEND; + if ((createFlags & BfpFileCreateFlag_Truncate) != 0) + flags |= O_TRUNC; + if ((createFlags & (BfpFileCreateFlag_NonBlocking | BfpFileCreateFlag_AllowTimeouts)) != 0) + flags |= O_NONBLOCK; + + if ((createFlags & BfpFileCreateFlag_Pipe) != 0) + { + name = "/tmp/" + name; + if ((createKind == BfpFileCreateKind_CreateAlways) || + (createKind == BfpFileCreateKind_CreateIfNotExists)) + { + for (int pass = 0; pass < 2; pass++) + { + int result = mknod(name.c_str(), S_IFIFO | 0666, 0); + if (result == 0) + break; + + int err = errno; + if (err == EEXIST) + { + err = remove(name.c_str()); + if (err == 0) + continue; + OUTRESULT(BfpFileResult_AlreadyExists); + return -1; + } + + OUTRESULT(BfpFileResult_UnknownError); + return -1; + } + } + } + else + { + if (createKind == BfpFileCreateKind_CreateAlways) + flags |= O_CREAT; + else if (createKind == BfpFileCreateKind_CreateIfNotExists) + flags |= O_CREAT | O_EXCL; + } + + mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; + + int result = open(name.c_str(), flags, mode); + //printf("BfpFile_Create %s %d %d %d\n", name.c_str(), result, flags, mode); + + if (result <= 0) + { + switch (errno) + { + case EEXIST: + OUTRESULT(BfpFileResult_AlreadyExists); + break; + case ENOENT: + OUTRESULT(BfpFileResult_NotFound); + break; + case EACCES: + OUTRESULT(BfpFileResult_AccessError); + break; + default: + OUTRESULT(BfpFileResult_UnknownError); + break; + } + return -1; + } + return result; + }; + + BfpFile* bfpFile = NULL; + + int result; + if ((createFlags & BfpFileCreateFlag_Pipe) != 0) + { + int readHandle; + int writeHandle; + + String name = inName; + String altName = name + "__"; + + bool isCreating = false; + if ((createKind == BfpFileCreateKind_CreateAlways) || + (createKind == BfpFileCreateKind_CreateIfNotExists)) + { + readHandle = _DoCreate(name); + writeHandle = _DoCreate(altName); + isCreating = true; + } + else + { + readHandle = _DoCreate(altName); + writeHandle = _DoCreate(name); + } + + if ((readHandle != -1) && (writeHandle != -1)) + { + OUTRESULT(BfpFileResult_Ok); + + BfpPipeInfo* pipeInfo = new BfpPipeInfo(); + pipeInfo->mWriteHandle = writeHandle; + if (isCreating) + pipeInfo->mPipePath = name; + bfpFile = new BfpFile(); + bfpFile->mHandle = readHandle; + bfpFile->mPipeInfo = pipeInfo; + } + else + { + if (readHandle != -1) + close(readHandle); + if (writeHandle != -1) + close(writeHandle); + + return NULL; + } + } + else + { + String name = inName; + int handle = _DoCreate(name); + if (handle == -1) + return NULL; + + OUTRESULT(BfpFileResult_Ok); + bfpFile = new BfpFile(); + bfpFile->mHandle = handle; + } + + OUTRESULT(BfpFileResult_Ok); + if ((createFlags & (BfpFileCreateFlag_NonBlocking | BfpFileCreateFlag_AllowTimeouts)) != 0) + bfpFile->mNonBlocking = true; + if ((createFlags & BfpFileCreateFlag_AllowTimeouts) != 0) + bfpFile->mAllowTimeout = true; + return bfpFile; +} + +BFP_EXPORT BfpFile* BFP_CALLTYPE BfpFile_GetStd(BfpFileStdKind kind, BfpFileResult* outResult) +{ + int h = -1; + switch (kind) + { + case BfpFileStdKind_StdOut: + h = STDOUT_FILENO; + break; + case BfpFileStdKind_StdError: + h = STDERR_FILENO; + break; + case BfpFileStdKind_StdIn: + h = STDIN_FILENO; + break; + } + if (h == -1) + { + OUTRESULT(BfpFileResult_NotFound); + return NULL; + } + + BfpFile* bfpFile = new BfpFile(); + bfpFile->mHandle = h; + bfpFile->mIsStd = true; + + return bfpFile; +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_Release(BfpFile* file) +{ + if ((file->mHandle != -1) && (!file->mIsStd)) + close(file->mHandle); + if (file->mPipeInfo != NULL) + { + if (file->mPipeInfo->mWriteHandle != -1) + close(file->mPipeInfo->mWriteHandle); + + if (!file->mPipeInfo->mPipePath.IsEmpty()) + { + int worked = remove(file->mPipeInfo->mPipePath.c_str()); + remove((file->mPipeInfo->mPipePath + "__").c_str()); + //printf("Removing %s %d\n", file->mPipeInfo->mPipePath.c_str(), worked); + } + } + + delete file; +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_Close(BfpFile* file, BfpFileResult* outResult) +{ + if (file->mHandle != -1) + { + close(file->mHandle); + file->mHandle = -1; + if (file->mPipeInfo != NULL) + { + close(file->mPipeInfo->mWriteHandle); + file->mPipeInfo->mWriteHandle = -1; + } + + OUTRESULT(BfpFileResult_Ok); + } + else + OUTRESULT(BfpFileResult_UnknownError); +} + +BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Write(BfpFile* file, const void* buffer, intptr size, int timeoutMS, BfpFileResult* outResult) +{ + int writeHandle = file->mHandle; + if (file->mPipeInfo != NULL) + writeHandle = file->mPipeInfo->mWriteHandle; + + intptr writeCount = ::write(writeHandle, buffer, size); +// if ((writeCount > 0) && (file->mIsPipe)) +// { +// ::fsync(file->mHandle); +// } + + if (writeCount < 0) + OUTRESULT(BfpFileResult_UnknownError); + else if (writeCount != size) + OUTRESULT(BfpFileResult_PartialData); + else + OUTRESULT(BfpFileResult_Ok); + return writeCount; +} + +BFP_EXPORT intptr BFP_CALLTYPE BfpFile_Read(BfpFile* file, void* buffer, intptr size, int timeoutMS, BfpFileResult* outResult) +{ + if (file->mNonBlocking) + { + if (!file->mAllowTimeout) + timeoutMS = -1; + + timeval timeout; + timeout.tv_sec = 0; + timeout.tv_usec = timeoutMS * 1000; + + fd_set readFDSet; + FD_ZERO(&readFDSet); + FD_SET(file->mHandle, &readFDSet); + + fd_set errorFDSet; + FD_ZERO(&errorFDSet); + FD_SET(file->mHandle, &errorFDSet); + + if (select(file->mHandle + 1, &readFDSet, NULL, &errorFDSet, (timeoutMS == -1) ? NULL : &timeout) < 0) + { + OUTRESULT(BfpFileResult_Timeout); + return 0; + } + } + + intptr readCount = ::read(file->mHandle, buffer, size); + if (readCount < 0) + OUTRESULT(BfpFileResult_UnknownError); + else if (readCount != size) + OUTRESULT(BfpFileResult_PartialData); + else + OUTRESULT(BfpFileResult_Ok); + return readCount; +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_Flush(BfpFile* file) +{ + ::fsync(file->mHandle); +} + +BFP_EXPORT int64 BFP_CALLTYPE BfpFile_GetFileSize(BfpFile* file) +{ + int64 oldPos = (int64)lseek64(file->mHandle, 0, SEEK_CUR); + int64 size = (int64)lseek64(file->mHandle, 0, SEEK_END); + lseek64(file->mHandle, oldPos, SEEK_SET); + return (int64)size; +} + +BFP_EXPORT int64 BFP_CALLTYPE BfpFile_Seek(BfpFile* file, int64 offset, BfpFileSeekKind seekKind) +{ + int whence; + if (seekKind == BfpFileSeekKind_Absolute) + whence = SEEK_SET; + else if (seekKind == BfpFileSeekKind_Relative) + whence = SEEK_CUR; + else + whence = SEEK_END; + return lseek64(file->mHandle, offset, whence); +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_Truncate(BfpFile* file) +{ + int64 curPos = (int64)lseek64(file->mHandle, 0, SEEK_CUR); + if (ftruncate64(file->mHandle, curPos) != 0) + { + //TODO: Report error? + } +} + +BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFile_GetTime_LastWrite(const char* path) +{ + struct stat statbuf = {0}; + int result = stat(path, &statbuf); + if (result != 0) + return 0; + return statbuf.st_mtime; +} + +BFP_EXPORT BfpFileAttributes BFP_CALLTYPE BfpFile_GetAttributes(const char* path, BfpFileResult* outResult) +{ + NOT_IMPL; + return (BfpFileAttributes)0; +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_SetAttributes(const char* path, BfpFileAttributes attribs, BfpFileResult* outResult) +{ + NOT_IMPL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_Copy(const char* oldPath, const char* newPath, BfpFileCopyKind copyKind, BfpFileResult* outResult) +{ + int fd_to, fd_from; + char buf[4096]; + ssize_t nread; + + fd_from = open(oldPath, O_RDONLY); + if (fd_from < 0) + { + OUTRESULT(BfpFileResult_NotFound); + return; + } + + int flags = O_WRONLY | O_CREAT; + if (copyKind == BfpFileCopyKind_IfNotExists) + flags |= O_EXCL; + + fd_to = open(newPath, flags, 0666); + if (fd_to < 0) + { + if (errno == EEXIST) + { + OUTRESULT(BfpFileResult_AlreadyExists); + goto out_error; + } + + OUTRESULT(BfpFileResult_UnknownError); + goto out_error; + } + + while (nread = read(fd_from, buf, sizeof buf), nread > 0) + { + char *out_ptr = buf; + ssize_t nwritten; + + do { + nwritten = write(fd_to, out_ptr, nread); + + if (nwritten >= 0) + { + nread -= nwritten; + out_ptr += nwritten; + } + else if (errno != EINTR) + { + OUTRESULT(BfpFileResult_UnknownError); + goto out_error; + } + } while (nread > 0); + } + + if (nread == 0) + { + if (close(fd_to) < 0) + { + fd_to = -1; + OUTRESULT(BfpFileResult_UnknownError); + goto out_error; + } + close(fd_from); + + /* Success! */ + OUTRESULT(BfpFileResult_Ok); + return; + } + +out_error: + close(fd_from); + if (fd_to >= 0) + close(fd_to); +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_Rename(const char* oldPath, const char* newPath, BfpFileResult* outResult) +{ + NOT_IMPL; +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_Delete(const char* path, BfpFileResult* outResult) +{ + if (remove(path) != 0) + { + switch (errno) + { + case ENOENT: + OUTRESULT(BfpFileResult_NotFound); + break; + default: + OUTRESULT(BfpFileResult_UnknownError); + break; + } + } + else + OUTRESULT(BfpFileResult_Ok); +} + +BFP_EXPORT bool BFP_CALLTYPE BfpFile_Exists(const char* path) +{ + struct stat statbuf = {0}; + int result = stat(path, &statbuf); + if (result != 0) + return false; + return !S_ISDIR(statbuf.st_mode); +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_GetTempPath(char* outPath, int* inOutPathSize, BfpFileResult* outResult) +{ + NOT_IMPL; +} + +static const char cHash64bToChar[] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', + 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', + 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', + 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '_' }; +static void HashEncode64(StringImpl& outStr, uint64 val) +{ + for (int i = 0; i < 10; i++) + { + int charIdx = (int)((val >> (i * 6)) & 0x3F) - 1; + if (charIdx != -1) + outStr.Append(cHash64bToChar[charIdx]); + } +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_GetTempFileName(char* outName, int* inOutNameSize, BfpFileResult* outResult) +{ + static uint32 uniqueIdx = 0; + BfpSystem_InterlockedExchangeAdd32(&uniqueIdx, 1); + + Beefy::HashContext ctx; + ctx.Mixin(uniqueIdx); + ctx.Mixin(getpid()); + ctx.Mixin(Beefy::BFGetTickCountMicro()); + + uint64 hash = ctx.Finish64(); + + String str = "/tmp/bftmp_"; + HashEncode64(str, hash); + + TryStringOut(str, outName, inOutNameSize, (BfpResult*)outResult); +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_GetFullPath(const char* inPath, char* outPath, int* inOutPathSize, BfpFileResult* outResult) +{ + String str; + + if (inPath[0] == '/') + { + str = inPath; + } + else + { + char* cwdPtr = getcwd(NULL, 0); + Beefy::String cwdPath = cwdPtr; + free(cwdPtr); + str = GetAbsPath(inPath, cwdPath); + } + TryStringOut(str, outPath, inOutPathSize, (BfpResult*)outResult); +} + +BFP_EXPORT void BFP_CALLTYPE BfpFile_GetActualPath(const char* inPath, char* outPath, int* inOutPathSize, BfpFileResult* outResult) +{ + NOT_IMPL; +} + +// BfpFindFileData + +struct BfpFindFileData +{ + BfpFindFileFlags mFlags; + DIR* mDirStruct; + Beefy::String mWildcard; + Beefy::String mDirPath; + + dirent* mDirEnt; + bool mHasStat; + struct stat mStat; +}; + +BFP_EXPORT BfpFindFileData* BFP_CALLTYPE BfpFindFileData_FindFirstFile(const char* path, BfpFindFileFlags flags, BfpFileResult* outResult) +{ + Beefy::String findStr = path; + Beefy::String wildcard; + + int lastSlashPos = std::max((int)findStr.LastIndexOf('/'), (int)findStr.LastIndexOf('\\')); + if (lastSlashPos != -1) + { + wildcard = findStr.Substring(lastSlashPos + 1); + findStr = findStr.Substring(0, lastSlashPos); + } + if (wildcard == "*.*") + wildcard = "*"; + + DIR* dir = opendir(findStr.c_str()); + if (dir == NULL) + { + OUTRESULT(BfpFileResult_NotFound); + return NULL; + } + + BfpFindFileData* findData = new BfpFindFileData(); + findData->mFlags = flags; + findData->mDirPath = findStr; + findData->mDirStruct = dir; + findData->mWildcard = wildcard; + findData->mHasStat = false; + findData->mDirEnt = NULL; + + if (!BfpFindFileData_FindNextFile(findData)) + { + OUTRESULT(BfpFileResult_NoResults); + delete findData; + return NULL; + } + + OUTRESULT(BfpFileResult_Ok); + return findData; +} + +static void GetStat(BfpFindFileData* findData) +{ + if (findData->mHasStat) + return; + + Beefy::String filePath = findData->mDirPath + "/" + findData->mDirEnt->d_name; + + findData->mStat = { 0 }; + int result = stat(filePath.c_str(), &findData->mStat); + + findData->mHasStat = true; +} + +static bool BfpFindFileData_CheckFilter(BfpFindFileData* findData) +{ + bool isDir = false; + if (findData->mDirEnt->d_type == DT_DIR) + isDir = true; + if (findData->mDirEnt->d_type == DT_LNK) + { + GetStat(findData); + isDir = S_ISDIR(findData->mStat.st_mode); + } + + if (isDir) + { + if ((findData->mFlags & BfpFindFileFlag_Directories) == 0) + return false; + + if ((strcmp(findData->mDirEnt->d_name, ".") == 0) || (strcmp(findData->mDirEnt->d_name, "..") == 0)) + return false; + } + else + { + if ((findData->mFlags & BfpFindFileFlag_Files) == 0) + return false; + } + + //TODO: Check actual wildcards. + + return true; +} + +BFP_EXPORT bool BFP_CALLTYPE BfpFindFileData_FindNextFile(BfpFindFileData* findData) +{ + while (true) + { + findData->mHasStat = false; + findData->mDirEnt = readdir(findData->mDirStruct); + if (findData->mDirEnt == NULL) + return false; + + if (BfpFindFileData_CheckFilter(findData)) + break; + } + + return true; +} + +BFP_EXPORT void BFP_CALLTYPE BfpFindFileData_GetFileName(BfpFindFileData* findData, char* outName, int* inOutNameSize, BfpFileResult* outResult) +{ + Beefy::String name = findData->mDirEnt->d_name; + TryStringOut(name, outName, inOutNameSize, (BfpResult*)outResult); +} + +BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_LastWrite(BfpFindFileData* findData) +{ + GetStat(findData); + return BfpToTimeStamp(findData->mStat.st_mtim); +} + +BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_Created(BfpFindFileData* findData) +{ + GetStat(findData); + return BfpToTimeStamp(findData->mStat.st_ctim); +} + +BFP_EXPORT BfpTimeStamp BFP_CALLTYPE BfpFindFileData_GetTime_Access(BfpFindFileData* findData) +{ + GetStat(findData); + return BfpToTimeStamp(findData->mStat.st_atim); +} + +BFP_EXPORT BfpFileAttributes BFP_CALLTYPE BfpFindFileData_GetFileAttributes(BfpFindFileData* findData) +{ + BfpFileAttributes flags = BfpFileAttribute_None; + if (S_ISDIR(findData->mStat.st_mode)) + flags = (BfpFileAttributes)(flags | BfpFileAttribute_Directory); + if (S_ISREG(findData->mStat.st_mode)) + flags = (BfpFileAttributes)(flags | BfpFileAttribute_Normal); + else if (!S_ISLNK(findData->mStat.st_mode)) + flags = (BfpFileAttributes)(flags | BfpFileAttribute_Device); + if ((findData->mStat.st_mode & S_IRUSR) == 0) + flags = (BfpFileAttributes)(flags | BfpFileAttribute_ReadOnly); + return flags; +} + +BFP_EXPORT void BFP_CALLTYPE BfpFindFileData_Release(BfpFindFileData* findData) +{ + delete findData; +} + +BFP_EXPORT int BFP_CALLTYPE BfpStack_CaptureBackTrace(int framesToSkip, intptr* outFrames, int wantFrameCount) +{ + // + return 0; +} + +BFP_EXPORT void BFP_CALLTYPE BfpOutput_DebugString(const char* str) +{ + BFP_PRINTF("%s", str); + fflush(stdout); +} + +////////////////////////////////////////////////////////////////////////// + +void Beefy::BFFatalError(const StringImpl& message, const StringImpl& file, int line) +{ + String error; + error += "ERROR: "; + error += message; + error += " in "; + error += file; + error += StrFormat(" line %d", line); + BfpSystem_FatalError(error.c_str(), "FATAL ERROR"); +} diff --git a/BeefySysLib/util/BeefPerf.cpp b/BeefySysLib/util/BeefPerf.cpp index d2b7ec2e1..202c22ef5 100644 --- a/BeefySysLib/util/BeefPerf.cpp +++ b/BeefySysLib/util/BeefPerf.cpp @@ -21,16 +21,14 @@ typedef fd_set FD_SET; #include #include #include -#include -//#define errno (*__error()) #endif -//#include +#ifdef BF_PLATFORM_POSIX +#include +#endif #pragma comment(lib,"wsock32.lib") -//#include "Hash.h" - #pragma warning(disable:4996) USING_NS_BF; diff --git a/BeefySysLib/util/Hash.cpp b/BeefySysLib/util/Hash.cpp index 0631c3685..a003325d4 100644 --- a/BeefySysLib/util/Hash.cpp +++ b/BeefySysLib/util/Hash.cpp @@ -1356,7 +1356,9 @@ static int gDbgVizIdx = 0; HashContext::~HashContext() { +#ifdef BF_PLATFORM_WINDOWS delete mDbgVizStream; +#endif } void HashContext::Reset() @@ -1378,6 +1380,7 @@ void HashContext::Mixin(const void* data, int size) { int addBytes = std::min(size, 1024 - mBufSize); +#ifdef BF_PLATFORM_WINDOWS if (mDbgViz) { int findIdx = 0x2cc159; @@ -1386,6 +1389,7 @@ void HashContext::Mixin(const void* data, int size) NOP; } } +#endif memcpy(&mBuf[mBufSize], data, addBytes); mBufSize += addBytes; @@ -1417,6 +1421,7 @@ void HashContext::MixinStr(const StringImpl& str) Val128 HashContext::Finish128() { +#ifdef BF_PLATFORM_WINDOWS if (mDbgViz) { // String dbg = "HashContext Dbg"; @@ -1441,6 +1446,7 @@ Val128 HashContext::Finish128() if ((mDbgVizStream != NULL) && (mDbgVizStream->IsOpen())) mDbgVizStream->Write(mBuf, mBufSize); } +#endif if (mBufSize <= 16) { @@ -1459,6 +1465,7 @@ Val128 HashContext::Finish128() uint64 HashContext::Finish64() { +#ifdef BF_PLATFORM_WINDOWS if (mDbgViz) { // String dbg = "HashContext Dbg"; @@ -1476,6 +1483,7 @@ uint64 HashContext::Finish64() } mDbgVizStream->Write(mBuf, mBufSize); } +#endif if (mBufSize <= 8) { diff --git a/BeefySysLib/util/Hash.h b/BeefySysLib/util/Hash.h index f86cf95c1..5ed4a66ca 100644 --- a/BeefySysLib/util/Hash.h +++ b/BeefySysLib/util/Hash.h @@ -109,16 +109,20 @@ class HashContext uint8 mBuf[1024]; int mBufSize; int mBufOffset; +#ifdef BF_PLATFORM_WINDOWS bool mDbgViz; FileStream* mDbgVizStream; +#endif public: HashContext() { mBufOffset = 0; mBufSize = 0; +#ifdef BF_PLATFORM_WINDOWS mDbgViz = false; mDbgVizStream = NULL; +#endif } ~HashContext(); diff --git a/IDE/src/BuildContext.bf b/IDE/src/BuildContext.bf index 6b07062ae..ba058b88b 100644 --- a/IDE/src/BuildContext.bf +++ b/IDE/src/BuildContext.bf @@ -157,9 +157,91 @@ namespace IDE return didCommands ? .HadCommands : .NoCommands; } + bool QueueProjectGNUArchive(Project project, String targetPath, Workspace.Options workspaceOptions, Project.Options options, String objectsArg) + { +#if BF_PLATFORM_WINDOWS + String llvmDir = scope String(IDEApp.sApp.mInstallDir); + IDEUtils.FixFilePath(llvmDir); + llvmDir.Append("llvm/"); +#else + String llvmDir = ""; +#endif + + //String error = scope String(); + + TestManager.ProjectInfo testProjectInfo = null; + if (gApp.mTestManager != null) + testProjectInfo = gApp.mTestManager.GetProjectInfo(project); + + bool isExe = (project.mGeneralOptions.mTargetType != Project.TargetType.BeefLib) || (testProjectInfo != null); + if (!isExe) + return true; + + String arCmds = scope String(""); //-O2 -Rpass=inline + //(doClangCPP ? "-lc++abi " : "") + + + arCmds.AppendF("CREATE {}\n", targetPath); + + for (let obj in objectsArg.Split(' ')) + { + if (!obj.IsEmpty) + { + arCmds.AppendF("ADDMOD {}\n", obj); + } + } + arCmds.AppendF("SAVE\n"); + + if (project.mNeedsTargetRebuild) + { + if (File.Delete(targetPath) case .Err) + { + gApp.OutputLine("Failed to delete {0}", targetPath); + return false; + } + + String arPath = scope .(); +#if BF_PLATFORM_WINDOWS + arPath.Clear(); + arPath.Append(gApp.mInstallDir); + arPath.Append(@"llvm\bin\llvm-ar.exe"); +#else + arPath.Append("/usr/bin/ar"); +#endif + + String workingDir = scope String(); + workingDir.Append(gApp.mInstallDir); + + String scriptPath = scope .(); + if (Path.GetTempFileName(scriptPath) case .Err) + { + return false; + } + if (File.WriteAllText(scriptPath, arCmds) case .Err) + { + gApp.OutputLine("Failed to write archive script {0}", scriptPath); + return false; + } + + String cmdLine = scope .(); + cmdLine.AppendF("-M"); + + var runCmd = gApp.QueueRun(arPath, cmdLine, workingDir, .UTF8); + runCmd.mOnlyIfNotFailed = true; + runCmd.mStdInData = new .(arCmds); + var tagetCompletedCmd = new IDEApp.TargetCompletedCmd(project); + tagetCompletedCmd.mOnlyIfNotFailed = true; + gApp.mExecutionQueue.Add(tagetCompletedCmd); + + project.mLastDidBuild = true; + } + + return true; + } + bool QueueProjectGNULink(Project project, String targetPath, Workspace.Options workspaceOptions, Project.Options options, String objectsArg) { bool isDebug = gApp.mConfigName.IndexOf("Debug", true) != -1; + #if BF_PLATFORM_WINDOWS String llvmDir = scope String(IDEApp.sApp.mInstallDir); @@ -1070,7 +1152,12 @@ namespace IDE if (workspaceOptions.mToolsetType == .GNU) { - if (!QueueProjectGNULink(project, targetPath, workspaceOptions, options, objectsArg)) + if ((options.mBuildOptions.mBuildKind == .StaticLib) || (options.mBuildOptions.mBuildKind == .DynamicLib)) + { + if (!QueueProjectGNUArchive(project, targetPath, workspaceOptions, options, objectsArg)) + return false; + } + else if (!QueueProjectGNULink(project, targetPath, workspaceOptions, options, objectsArg)) return false; } else // MS diff --git a/IDE/src/BuildOptions.bf b/IDE/src/BuildOptions.bf index ebe0cc4fc..7e54fa28a 100644 --- a/IDE/src/BuildOptions.bf +++ b/IDE/src/BuildOptions.bf @@ -45,6 +45,25 @@ namespace IDE return (this != .Og) && (this != .OgPlus) && (this != .O0); } } + + public enum RelocType + { + NotSet, + Static, + PIC, + DynamicNoPIC, + ROPI, + RWPI, + ROPI_RWPI + } + + public enum PICLevel + { + NotSet, + Not, + Small, + Big + } } public class DistinctBuildOptions diff --git a/IDE/src/Compiler/BfCompiler.bf b/IDE/src/Compiler/BfCompiler.bf index e65b1ef7a..d03f19bf2 100644 --- a/IDE/src/Compiler/BfCompiler.bf +++ b/IDE/src/Compiler/BfCompiler.bf @@ -7,6 +7,7 @@ using System.Diagnostics; using Beefy.widgets; using Beefy; using Beefy.utils; +using IDE.Util; namespace IDE.Compiler { @@ -465,7 +466,10 @@ namespace IDE.Compiler var options = IDEApp.sApp.GetCurWorkspaceOptions(); String targetTriple = scope .(); - Workspace.PlatformType.GetTargetTripleByName(gApp.mPlatformName, options.mToolsetType, targetTriple); + if (TargetTriple.IsTargetTriple(gApp.mPlatformName)) + targetTriple.Set(gApp.mPlatformName); + else + Workspace.PlatformType.GetTargetTripleByName(gApp.mPlatformName, options.mToolsetType, targetTriple); bool enableObjectDebugFlags = options.mEnableObjectDebugFlags; bool emitObjectAccessCheck = options.mEmitObjectAccessCheck && enableObjectDebugFlags; diff --git a/IDE/src/Compiler/BfProject.bf b/IDE/src/Compiler/BfProject.bf index 348fc48f7..f44bcd2de 100644 --- a/IDE/src/Compiler/BfProject.bf +++ b/IDE/src/Compiler/BfProject.bf @@ -34,7 +34,7 @@ namespace IDE.Compiler [StdCall, CLink] extern static void BfProject_SetOptions(void* nativeBfProject, int32 targetType, char8* startupObject, char8* preprocessorMacros, - int32 optLevel, int32 ltoType, Flags flags); + int32 optLevel, int32 ltoType, int32 relocType, int32 picLevel, Flags flags); public void* mNativeBfProject; public bool mDisabled; @@ -61,7 +61,8 @@ namespace IDE.Compiler } public void SetOptions(Project.TargetType targetType, String startupObject, List preprocessorMacros, - BuildOptions.BfOptimizationLevel optLevel, BuildOptions.LTOType ltoType, bool mergeFunctions, bool combineLoads, bool vectorizeLoops, bool vectorizeSLP) + BuildOptions.BfOptimizationLevel optLevel, BuildOptions.LTOType ltoType, BuildOptions.RelocType relocType, BuildOptions.PICLevel picLevel, + bool mergeFunctions, bool combineLoads, bool vectorizeLoops, bool vectorizeSLP) { Flags flags = default; void SetFlags(bool val, Flags flag) @@ -77,7 +78,7 @@ namespace IDE.Compiler String macrosStr = scope String(); macrosStr.Join("\n", preprocessorMacros.GetEnumerator()); BfProject_SetOptions(mNativeBfProject, (int32)targetType, startupObject, macrosStr, - (int32)optLevel, (int32)ltoType, flags); + (int32)optLevel, (int32)ltoType, (int32)relocType, (int32)picLevel, flags); } } diff --git a/IDE/src/IDEApp.bf b/IDE/src/IDEApp.bf index 5508d8493..2b09d6451 100644 --- a/IDE/src/IDEApp.bf +++ b/IDE/src/IDEApp.bf @@ -420,6 +420,7 @@ namespace IDE public ArgsFileKind mUseArgsFile; public int32 mParallelGroup = -1; public bool mIsTargetRun; + public String mStdInData ~ delete _; } public List mExecutionQueue = new List() ~ DeleteContainerAndItems!(_); @@ -435,9 +436,11 @@ namespace IDE public Task mErrorTask /*~ delete _*/; public Action> mOnErrorTaskComplete /*~ delete _*/; public Monitor mMonitor = new Monitor() ~ delete _; + public String mStdInData ~ delete _; public Thread mOutputThread; public Thread mErrorThread; + public Thread mInputThread; public int? mExitCode; public bool mAutoDelete = true; @@ -450,12 +453,17 @@ namespace IDE /*if (mProcess != null) mProcess.Close();*/ + if (mInputThread != null) + mInputThread.Join(); + delete mInputThread; + if (mOutputThread != null) mOutputThread.Join(); delete mOutputThread; + if (mErrorThread != null) mErrorThread.Join(); - delete mErrorThread; + delete mErrorThread; delete mReadTask; delete mOnReadTaskComplete; @@ -7092,6 +7100,26 @@ namespace IDE } } + static void WriteInputThread(Object obj) + { + ExecutionInstance executionInstance = (ExecutionInstance)obj; + + FileStream fileStream = scope FileStream(); + if (executionInstance.mProcess.AttachStandardInput(fileStream) case .Err) + return; + + while (!executionInstance.mStdInData.IsEmpty) + { + switch (fileStream.TryWrite(.((.)executionInstance.mStdInData.Ptr, executionInstance.mStdInData.Length))) + { + case .Ok(int len): + executionInstance.mStdInData.Remove(0, len); + case .Err: + break; + } + } + } + static void ReadOutputThread(Object obj) { ExecutionInstance executionInstance = (ExecutionInstance)obj; @@ -7131,7 +7159,7 @@ namespace IDE } } - public ExecutionInstance DoRun(String inFileName, String args, String workingDir, ArgsFileKind useArgsFile, Dictionary envVars = null) + public ExecutionInstance DoRun(String inFileName, String args, String workingDir, ArgsFileKind useArgsFile, Dictionary envVars = null, String stdInData = null) { //Debug.Assert(executionInstance == null); @@ -7146,6 +7174,8 @@ namespace IDE startInfo.SetArguments(args); startInfo.RedirectStandardOutput = true; startInfo.RedirectStandardError = true; + if (stdInData != null) + startInfo.RedirectStandardInput = true; startInfo.CreateNoWindow = true; if (envVars != null) { @@ -7224,6 +7254,13 @@ namespace IDE executionInstance.mErrorThread = new Thread(new => ReadErrorThread); executionInstance.mErrorThread.Start(executionInstance, false); + if (stdInData != null) + { + executionInstance.mStdInData = new String(stdInData); + executionInstance.mInputThread = new Thread(new => WriteInputThread); + executionInstance.mInputThread.Start(executionInstance, false); + } + return executionInstance; } @@ -7502,7 +7539,7 @@ namespace IDE else if (next is ExecutionQueueCmd) { var executionQueueCmd = (ExecutionQueueCmd)next; - var executionInstance = DoRun(executionQueueCmd.mFileName, executionQueueCmd.mArgs, executionQueueCmd.mWorkingDir, executionQueueCmd.mUseArgsFile, executionQueueCmd.mEnvVars); + var executionInstance = DoRun(executionQueueCmd.mFileName, executionQueueCmd.mArgs, executionQueueCmd.mWorkingDir, executionQueueCmd.mUseArgsFile, executionQueueCmd.mEnvVars, executionQueueCmd.mStdInData); executionInstance.mParallelGroup = executionQueueCmd.mParallelGroup; executionInstance.mIsTargetRun = executionQueueCmd.mIsTargetRun; } @@ -7903,12 +7940,23 @@ namespace IDE success = false; } } + else if (options.mBuildOptions.mBuildKind == .StaticLib) + { + if (project.mGeneralOptions.mTargetType.IsBeefApplication) + targetType = .BeefApplication_StaticLib; + } + else if (options.mBuildOptions.mBuildKind == .DynamicLib) + { + if (project.mGeneralOptions.mTargetType.IsBeefApplication) + targetType = .BeefApplication_DynamicLib; + } } bfProject.SetOptions(targetType, project.mBeefGlobalOptions.mStartupObject, preprocessorMacros.mDefines, - optimizationLevel, ltoType, options.mBeefOptions.mMergeFunctions, options.mBeefOptions.mCombineLoads, + optimizationLevel, ltoType, options.mBeefOptions.mRelocType, options.mBeefOptions.mPICLevel, + options.mBeefOptions.mMergeFunctions, options.mBeefOptions.mCombineLoads, options.mBeefOptions.mVectorizeLoops, options.mBeefOptions.mVectorizeSLP); List depProjectList = scope List(); @@ -8378,21 +8426,43 @@ namespace IDE return false; let platformType = Workspace.PlatformType.GetFromName(platformName); - switch (platformType) + + if (options.mBuildOptions.mBuildKind.IsApplicationLib) { - case .Windows: - if (project.mGeneralOptions.mTargetType == .BeefLib) - newString.Append(".lib"); - else if (project.mGeneralOptions.mTargetType == .BeefDynLib) - newString.Append(".dll"); - else if (project.mGeneralOptions.mTargetType != .CustomBuild) - newString.Append(".exe"); - case .macOS: - if (project.mGeneralOptions.mTargetType == Project.TargetType.BeefLib) - newString.Append(".dylib"); - default: - if (project.mGeneralOptions.mTargetType == Project.TargetType.BeefLib) - newString.Append(".so"); + switch (platformType) + { + case .Windows: + newString.Append(".lib"); + case .iOS: + if (options.mBuildOptions.mBuildKind == .DynamicLib) + newString.Append(".dylib"); + else + newString.Append(".a"); + default: + if (options.mBuildOptions.mBuildKind == .DynamicLib) + newString.Append(".so"); + else + newString.Append(".a"); + } + } + else + { + switch (platformType) + { + case .Windows: + if (project.mGeneralOptions.mTargetType == .BeefLib) + newString.Append(".lib"); + else if (project.mGeneralOptions.mTargetType == .BeefDynLib) + newString.Append(".dll"); + else if (project.mGeneralOptions.mTargetType != .CustomBuild) + newString.Append(".exe"); + case .macOS: + if (project.mGeneralOptions.mTargetType == Project.TargetType.BeefLib) + newString.Append(".dylib"); + default: + if (project.mGeneralOptions.mTargetType == Project.TargetType.BeefLib) + newString.Append(".so"); + } } } case "ProjectDir": @@ -8633,7 +8703,10 @@ namespace IDE else { clangOptions.Append("--target="); - Workspace.PlatformType.GetTargetTripleByName(gApp.mPlatformName, workspaceOptions.mToolsetType, clangOptions); + if (TargetTriple.IsTargetTriple(gApp.mPlatformName)) + clangOptions.Append(gApp.mPlatformName); + else + Workspace.PlatformType.GetTargetTripleByName(gApp.mPlatformName, workspaceOptions.mToolsetType, clangOptions); clangOptions.Append(" "); if (workspaceOptions.mToolsetType == .GNU) diff --git a/IDE/src/Project.bf b/IDE/src/Project.bf index 21b09601e..1e5bf919f 100644 --- a/IDE/src/Project.bf +++ b/IDE/src/Project.bf @@ -792,6 +792,16 @@ namespace IDE { case Normal; case Test; + case StaticLib; + case DynamicLib; + + public bool IsApplicationLib + { + get + { + return (this == .StaticLib) || (this == .DynamicLib); + } + } } public enum COptimizationLevel @@ -838,20 +848,39 @@ namespace IDE CustomBuild, C_ConsoleApplication, C_WindowsApplication, - BeefTest; + BeefTest, + BeefApplication_StaticLib, + BeefApplication_DynamicLib; public bool IsBeef { - get - { - switch (this) - { - case BeefConsoleApplication, - BeefWindowsApplication, - BeefLib, - BeefDynLib, - BeefTest: return true; - default: return false; + get + { + switch (this) + { + case BeefConsoleApplication, + BeefWindowsApplication, + BeefLib, + BeefDynLib, + BeefTest: + return true; + default: + return false; + } + } + } + + public bool IsBeefApplication + { + get + { + switch (this) + { + case BeefConsoleApplication, + BeefWindowsApplication: + return true; + default: + return false; } } } @@ -1005,6 +1034,10 @@ namespace IDE [Reflect] public List mPreprocessorMacros = new List() ~ DeleteContainerAndItems!(_); [Reflect] + public BuildOptions.RelocType mRelocType; + [Reflect] + public BuildOptions.PICLevel mPICLevel; + [Reflect] public BuildOptions.BfOptimizationLevel? mOptimizationLevel; [Reflect] public BuildOptions.LTOType? mLTOType; @@ -1103,6 +1136,8 @@ namespace IDE Set!(newOptions.mBeefOptions.mPreprocessorMacros, mBeefOptions.mPreprocessorMacros); Set!(newOptions.mBeefOptions.mOptimizationLevel, mBeefOptions.mOptimizationLevel); Set!(newOptions.mBeefOptions.mLTOType, mBeefOptions.mLTOType); + Set!(newOptions.mBeefOptions.mRelocType, mBeefOptions.mRelocType); + Set!(newOptions.mBeefOptions.mPICLevel, mBeefOptions.mPICLevel); Set!(newOptions.mBeefOptions.mMergeFunctions, mBeefOptions.mMergeFunctions); Set!(newOptions.mBeefOptions.mCombineLoads, mBeefOptions.mCombineLoads); Set!(newOptions.mBeefOptions.mVectorizeLoops, mBeefOptions.mVectorizeLoops); @@ -1522,6 +1557,8 @@ namespace IDE data.Add(macro); } } + data.ConditionalAdd("RelocType", options.mBeefOptions.mRelocType, .NotSet); + data.ConditionalAdd("PICLevel", options.mBeefOptions.mPICLevel, .NotSet); data.ConditionalAdd("OptimizationLevel", options.mBeefOptions.mOptimizationLevel); data.ConditionalAdd("LTOType", options.mBeefOptions.mLTOType); data.ConditionalAdd("MergeFunctions", options.mBeefOptions.mMergeFunctions); @@ -1826,6 +1863,8 @@ namespace IDE options.mBeefOptions.mPreprocessorMacros.Add(new String("TEST")); } + options.mBeefOptions.mRelocType = data.GetEnum("RelocType"); + options.mBeefOptions.mPICLevel = data.GetEnum("PICLevel"); if (data.Contains("OptimizationLevel")) options.mBeefOptions.mOptimizationLevel = data.GetEnum("OptimizationLevel"); if (data.Contains("LTOType")) @@ -2135,6 +2174,7 @@ namespace IDE bool isParanoid = configName.Contains("Paranoid"); bool isDebug = isParanoid || configName.Contains("Debug"); bool isTest = configName.Contains("Test"); + let platformType = Workspace.PlatformType.GetFromName(platformName); if (isRelease) options.mBeefOptions.mPreprocessorMacros.Add(new String("RELEASE")); @@ -2149,7 +2189,20 @@ namespace IDE options.mBuildOptions.mBeefLibType = isRelease ? .Static : .Dynamic; options.mBuildOptions.mStackSize = 0; - options.mBuildOptions.mBuildKind = isTest ? .Test : .Normal; + switch (platformType) + { + case .Linux, + .Windows, + .macOS: + options.mBuildOptions.mBuildKind = isTest ? .Test : .Normal; + default: + options.mBuildOptions.mBuildKind = .StaticLib; + } + + if (platformType == .Android) + { + options.mBeefOptions.mRelocType = .PIC; + } options.mBuildOptions.mOtherLinkFlags.Set("$(LinkFlags)"); diff --git a/IDE/src/Workspace.bf b/IDE/src/Workspace.bf index 3b9e37cbe..dadb99f7b 100644 --- a/IDE/src/Workspace.bf +++ b/IDE/src/Workspace.bf @@ -27,6 +27,7 @@ namespace IDE case Linux; case macOS; case iOS; + case Android; public static PlatformType GetFromName(String name) { @@ -36,7 +37,8 @@ namespace IDE case "Linux32", "Linux64": return .Linux; case "macOS": return .macOS; case "iOS": return .iOS; - default: return .Unknown; + default: + return TargetTriple.GetPlatformType(name); } } @@ -60,7 +62,11 @@ namespace IDE public static int GetPtrSizeByName(String name) { - if (name.EndsWith("32")) + if ((name.EndsWith("32")) && (!TargetTriple.IsTargetTriple(name))) + return 4; + if (name.StartsWith("armv")) + return 4; + if (name.StartsWith("i686-")) return 4; return 8; } @@ -80,7 +86,7 @@ namespace IDE case "macOS": outTriple.Append("x86_64-apple-macosx10.14.0"); case "iOS": - outTriple.Append("aarch64-apple-ios"); + outTriple.Append("arm64-apple-ios"); default: return false; } @@ -167,6 +173,8 @@ namespace IDE { [Reflect] public List mPreprocessorMacros = new List() ~ DeleteContainerAndItems!(_); + /*[Reflect] + public String mTargetTriple = new .() ~ delete _;*/ [Reflect] public List mDistinctBuildOptions = new List() ~ DeleteContainerAndItems!(_); } @@ -505,6 +513,7 @@ namespace IDE if (mStartupProject != null) data.Add("StartupProject", mStartupProject.mProjectName); WriteStrings("PreprocessorMacros", mBeefGlobalOptions.mPreprocessorMacros); + //data.ConditionalAdd("TargetTriple", mBeefGlobalOptions.mTargetTriple, ""); WriteDistinctOptions(mBeefGlobalOptions.mDistinctBuildOptions); data.RemoveIfEmpty(); } @@ -697,15 +706,20 @@ namespace IDE bool isTest = configName.Contains("Test"); let platformType = PlatformType.GetFromName(platformName); + /*if (TargetTriple.IsTargetTriple(platformName)) + { + options.mToolsetType = .None; + }*/ + + options.mBfOptimizationLevel = isRelease ? .O2 : .O0; options.mBfSIMDSetting = .SSE2; if (platformType == .Windows) { options.mBfOptimizationLevel = isRelease ? .O2 : (platformName == "Win64") ? .OgPlus : .O0; options.mToolsetType = .Microsoft; } - else + else if ((platformType == .macOS) == (platformType == .Linux)) { - options.mBfOptimizationLevel = isRelease ? .O2 : .O0; options.mToolsetType = .GNU; } @@ -757,6 +771,7 @@ namespace IDE data.GetCurString(str); mBeefGlobalOptions.mPreprocessorMacros.Add(str); } + //data.GetString("TargetTriple", mBeefGlobalOptions.mTargetTriple); for (data.Enumerate("DistinctOptions")) { diff --git a/IDE/src/ui/ProjectProperties.bf b/IDE/src/ui/ProjectProperties.bf index 7e533c7ac..a47a65ab3 100644 --- a/IDE/src/ui/ProjectProperties.bf +++ b/IDE/src/ui/ProjectProperties.bf @@ -823,7 +823,9 @@ namespace IDE.ui (category, propEntry) = AddPropertiesItem(root, "Code Generation"); category.mIsBold = true; - category.mTextColor = cHeaderColor; + category.mTextColor = cHeaderColor; + AddPropertiesItem(category, "Reloc Model", "mBeefOptions.mRelocType"); + AddPropertiesItem(category, "PIC Level", "mBeefOptions.mPICLevel"); AddPropertiesItem(category, "Optimization Level", "mBeefOptions.mOptimizationLevel", scope String[] { "O0", "O1", "O2", "O3", "Og", "Og+" }); // -O0 .. -O3, -Os, -Ofast, -Og AddPropertiesItem(category, "LTO", "mBeefOptions.mLTOType"); diff --git a/IDE/src/ui/WorkspaceProperties.bf b/IDE/src/ui/WorkspaceProperties.bf index e85469329..7019f2bb3 100644 --- a/IDE/src/ui/WorkspaceProperties.bf +++ b/IDE/src/ui/WorkspaceProperties.bf @@ -724,17 +724,20 @@ namespace IDE.ui void PopulateBeefGlobalOptions() { var root = (DarkListViewItem)mPropPage.mPropertiesListView.GetRoot(); - var (category, ?) = AddPropertiesItem(root, "General"); + /*var (category, ?) = AddPropertiesItem(root, "General"); category.mIsBold = true; - category.mTextColor = 0xFFE8E8E8; + category.mTextColor = 0xFFE8E8E8;*/ - AddPropertiesItem(category, "Preprocessor Macros", "mPreprocessorMacros"); + AddPropertiesItem(root, "Preprocessor Macros", "mPreprocessorMacros"); DistinctOptionBuilder dictinctOptionBuilder = scope .(this); dictinctOptionBuilder.Add(gApp.mWorkspace.mBeefGlobalOptions.mDistinctBuildOptions); dictinctOptionBuilder.Finish(); + + //AddPropertiesItem(root, "Target Triple", "mTargetTriple"); + AddNewDistinctBuildOptions(); //parent.MakeParent(); - category.Open(true, true); + //category.Open(true, true); } void PopulateBeefTargetedOptions() diff --git a/IDE/src/util/TargetTriple.bf b/IDE/src/util/TargetTriple.bf new file mode 100644 index 000000000..dbfae7e2c --- /dev/null +++ b/IDE/src/util/TargetTriple.bf @@ -0,0 +1,55 @@ +using System; + +namespace IDE.Util +{ + class TargetTriple + { + public static bool IsTargetTriple(StringView str) + { + int dashCount = 0; + for (let c in str.RawChars) + if (c == '-') + dashCount++; + return dashCount >= 2; + } + + public static Workspace.PlatformType GetPlatformType(StringView str) + { + var str; + + // Remove version from the end + while (!str.IsEmpty) + { + char8 c = str[str.Length - 1]; + if ((c.IsDigit) || (c == '.')) + str.RemoveFromEnd(1); + else + break; + } + + bool hasLinux = false; + + for (let elem in str.Split('-')) + { + switch (elem) + { + case "linux": + hasLinux = true; + case "windows": + return .Windows; + case "macosx": + return .macOS; + case "ios": + return .iOS; + case "android", + "androideabi": + return .Android; + } + } + + if (hasLinux) + return .Linux; + return .Unknown; + } + } +} diff --git a/IDEHelper/Compiler/BfCompiler.cpp b/IDEHelper/Compiler/BfCompiler.cpp index 6815436b5..32d6c1c56 100644 --- a/IDEHelper/Compiler/BfCompiler.cpp +++ b/IDEHelper/Compiler/BfCompiler.cpp @@ -1582,7 +1582,7 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) BfIRFunctionType mainFuncType; BfIRFunction mainFunc; if ((project->mTargetType == BfTargetType_BeefConsoleApplication) || (project->mTargetType == BfTargetType_BeefTest)) - { + { SmallVector paramTypes; paramTypes.push_back(int32Type); paramTypes.push_back(nullPtrType); @@ -1598,7 +1598,7 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) paramTypes.push_back(nullPtrType); // lpvReserved mainFuncType = bfModule->mBfIRBuilder->CreateFunctionType(int32Type, paramTypes, false); mainFunc = bfModule->mBfIRBuilder->CreateFunction(mainFuncType, BfIRLinkageType_External, "DllMain"); - if (mSystem->mPtrSize == 4) + if (mOptions.mMachineType == BfMachineType_x86) bfModule->mBfIRBuilder->SetFuncCallingConv(mainFunc, BfIRCallingConv_StdCall); bfModule->SetupIRMethod(NULL, mainFunc, false); } @@ -1611,7 +1611,7 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) paramTypes.push_back(int32Type); // nCmdShow mainFuncType = bfModule->mBfIRBuilder->CreateFunctionType(int32Type, paramTypes, false); mainFunc = bfModule->mBfIRBuilder->CreateFunction(mainFuncType, BfIRLinkageType_External, "WinMain"); - if (mSystem->mPtrSize == 4) + if (mOptions.mMachineType == BfMachineType_x86) bfModule->mBfIRBuilder->SetFuncCallingConv(mainFunc, BfIRCallingConv_StdCall); bfModule->SetupIRMethod(NULL, mainFunc, false); } @@ -1620,7 +1620,7 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) SmallVector paramTypes; paramTypes.push_back(int32Type); paramTypes.push_back(nullPtrType); - mainFuncType = bfModule->mBfIRBuilder->CreateFunctionType(voidType, paramTypes, false); + mainFuncType = bfModule->mBfIRBuilder->CreateFunctionType(int32Type, paramTypes, false); mainFunc = bfModule->mBfIRBuilder->CreateFunction(mainFuncType, BfIRLinkageType_External, "BeefMain"); bfModule->SetupIRMethod(NULL, mainFunc, false); } @@ -1711,7 +1711,8 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) } BfIRValue retValue; - if ((project->mTargetType == BfTargetType_BeefConsoleApplication) || (project->mTargetType == BfTargetType_BeefWindowsApplication)) + if ((project->mTargetType == BfTargetType_BeefConsoleApplication) || (project->mTargetType == BfTargetType_BeefWindowsApplication) || + (project->mTargetType == BfTargetType_BeefApplication_StaticLib) || (project->mTargetType == BfTargetType_BeefApplication_DynamicLib)) { bool hadRet = false; @@ -1785,7 +1786,7 @@ void BfCompiler::CreateVData(BfVDataModule* bfModule) } BfIRFunctionType thunkFuncType = bfModule->mBfIRBuilder->CreateFunctionType(int32Type, paramTypes, false); - BfIRFunction thunkMainFunc = bfModule->mBfIRBuilder->CreateFunction(thunkFuncType, BfIRLinkageType_External, "BeefMain"); + BfIRFunction thunkMainFunc = bfModule->mBfIRBuilder->CreateFunction(thunkFuncType, BfIRLinkageType_External, "BeefStartProgram"); bfModule->SetupIRMethod(NULL, thunkMainFunc, false); bfModule->mBfIRBuilder->SetActiveFunction(thunkMainFunc); @@ -5879,7 +5880,8 @@ bool BfCompiler::DoCompile(const StringImpl& outputDirectory) if ((bfProject->mTargetType != BfTargetType_BeefConsoleApplication) && (bfProject->mTargetType != BfTargetType_BeefWindowsApplication) && (bfProject->mTargetType != BfTargetType_BeefDynLib) && (bfProject->mTargetType != BfTargetType_C_ConsoleApplication) && (bfProject->mTargetType != BfTargetType_C_WindowsApplication) && - (bfProject->mTargetType != BfTargetType_BeefTest)) + (bfProject->mTargetType != BfTargetType_BeefTest) && + (bfProject->mTargetType != BfTargetType_BeefApplication_StaticLib) && (bfProject->mTargetType != BfTargetType_BeefApplication_DynamicLib)) continue; if (bfProject->mTargetType == BfTargetType_BeefTest) @@ -8122,6 +8124,38 @@ BF_EXPORT const char* BF_CALLTYPE BfCompiler_HotResolve_Finish(BfCompiler* bfCom return outString.c_str(); } +static BfPlatformType GetPlatform(StringView str) +{ + while (!str.IsEmpty()) + { + char c = str[str.mLength - 1]; + if (((c >= '0') && (c <= '9')) || (c == '.')) + str.RemoveFromEnd(1); + else + break; + } + + bool hasLinux = false; + + for (auto elem : str.Split('-')) + { + if (elem == "linux") + hasLinux = true; + else if (elem == "windows") + return BfPlatformType_Windows; + else if (elem == "macosx") + return BfPlatformType_macOS; + else if (elem == "ios") + return BfPlatformType_iOS; + else if ((elem == "android") || (elem == "androideabi")) + return BfPlatformType_Android; + } + + if (hasLinux) + return BfPlatformType_Linux; + return BfPlatformType_Unknown; +} + BF_EXPORT void BF_CALLTYPE BfCompiler_SetOptions(BfCompiler* bfCompiler, BfProject* hotProject, int hotIdx, const char* targetTriple, int toolsetType, int simdSetting, int allocStackCount, int maxWorkerThreads, BfCompilerOptionFlags optionFlags, char* mallocLinkName, char* freeLinkName) @@ -8141,9 +8175,22 @@ BF_EXPORT void BF_CALLTYPE BfCompiler_SetOptions(BfCompiler* bfCompiler, BfProje options->mMachineType = BfMachineType_x64; else if (options->mTargetTriple.StartsWith("i686-")) options->mMachineType = BfMachineType_x86; + else if ((options->mTargetTriple.StartsWith("arm64")) || (options->mTargetTriple.StartsWith("aarch64"))) + options->mMachineType = BfMachineType_AArch64; + else if (options->mTargetTriple.StartsWith("armv")) + options->mMachineType = BfMachineType_ARM; else options->mMachineType = BfMachineType_x64; // Default + options->mPlatformType = GetPlatform(options->mTargetTriple); + + options->mCLongSize = 4; + if ((options->mMachineType == BfMachineType_AArch64) || (options->mMachineType == BfMachineType_x64)) + { + if ((options->mPlatformType == BfPlatformType_macOS) || (options->mPlatformType == BfPlatformType_iOS) || (options->mPlatformType == BfPlatformType_Android)) + options->mCLongSize = 8; + } + bfCompiler->mCodeGen.SetMaxThreads(maxWorkerThreads); if (!bfCompiler->mIsResolveOnly) @@ -8169,15 +8216,15 @@ BF_EXPORT void BF_CALLTYPE BfCompiler_SetOptions(BfCompiler* bfCompiler, BfProje options->mOmitDebugHelpers = (optionFlags & BfCompilerOptionFlag_OmitDebugHelpers) != 0; #ifdef _WINDOWS - if (options->mToolsetType == BfToolsetType_GNU) - { - options->mErrorString = "Toolset 'GNU' is not available on this platform. Consider changing 'Workspace/General/Toolset'."; - } +// if (options->mToolsetType == BfToolsetType_GNU) +// { +// options->mErrorString = "Toolset 'GNU' is not available on this platform. Consider changing 'Workspace/General/Toolset'."; +// } #else - if (options->mToolsetType == BfToolsetType_Microsoft) - { - options->mErrorString = "Toolset 'Microsoft' is not available on this platform. Consider changing 'Workspace/General/Toolset'."; - } +// if (options->mToolsetType == BfToolsetType_Microsoft) +// { +// options->mErrorString = "Toolset 'Microsoft' is not available on this platform. Consider changing 'Workspace/General/Toolset'."; +// } BF_ASSERT(!options->mEnableRealtimeLeakCheck); #endif options->mEmitObjectAccessCheck = (optionFlags & BfCompilerOptionFlag_EmitDebugInfo) != 0; diff --git a/IDEHelper/Compiler/BfCompiler.h b/IDEHelper/Compiler/BfCompiler.h index c4fb7edd0..fe6b6fa0f 100644 --- a/IDEHelper/Compiler/BfCompiler.h +++ b/IDEHelper/Compiler/BfCompiler.h @@ -94,13 +94,15 @@ class BfCompiler int32 mForceRebuildIdx; BfCompileOnDemandKind mCompileOnDemandKind; String mTargetTriple; + BfPlatformType mPlatformType; BfMachineType mMachineType; + int mCLongSize; BfToolsetType mToolsetType; BfSIMDSetting mSIMDSetting; int mMaxWorkerThreads; String mMallocLinkName; String mFreeLinkName; - bool mIncrementalBuild; + bool mIncrementalBuild; bool mEmitDebugInfo; bool mEmitLineInfo; @@ -140,7 +142,9 @@ class BfCompiler mHotCompileIdx = 0; mForceRebuildIdx = 0; mCompileOnDemandKind = BfCompileOnDemandKind_AlwaysInclude; + mPlatformType = BfPlatformType_Unknown; mMachineType = BfMachineType_x86; + mCLongSize = 4; mToolsetType = BfToolsetType_Microsoft; mSIMDSetting = BfSIMDSetting_None; mHotProject = NULL; diff --git a/IDEHelper/Compiler/BfContext.cpp b/IDEHelper/Compiler/BfContext.cpp index 5665540c5..e2c907a7f 100644 --- a/IDEHelper/Compiler/BfContext.cpp +++ b/IDEHelper/Compiler/BfContext.cpp @@ -1632,7 +1632,8 @@ void BfContext::UpdateRevisedTypes() BP_ZONE("BfContext::UpdateRevisedTypes"); int wantPtrSize; - if (mCompiler->mOptions.mMachineType == BfMachineType_x86) + if ((mCompiler->mOptions.mMachineType == BfMachineType_x86) | + (mCompiler->mOptions.mMachineType == BfMachineType_ARM)) wantPtrSize = 4; else wantPtrSize = 8; @@ -1788,9 +1789,12 @@ void BfContext::UpdateRevisedTypes() // { + AutoCrit autoCrit(mSystem->mDataLock); + auto options = &mCompiler->mOptions; HashContext workspaceConfigHashCtx; + workspaceConfigHashCtx.MixinStr(options->mTargetTriple); workspaceConfigHashCtx.Mixin(options->mForceRebuildIdx); workspaceConfigHashCtx.Mixin(options->mMachineType); @@ -1813,6 +1817,8 @@ void BfContext::UpdateRevisedTypes() workspaceConfigHashCtx.Mixin(options->mEnableCustodian); workspaceConfigHashCtx.Mixin(options->mEnableSideStack); workspaceConfigHashCtx.Mixin(options->mHasVDataExtender); + workspaceConfigHashCtx.Mixin(options->mDebugAlloc); + workspaceConfigHashCtx.Mixin(options->mOmitDebugHelpers); workspaceConfigHashCtx.Mixin(options->mUseDebugBackingParams); @@ -1821,6 +1827,7 @@ void BfContext::UpdateRevisedTypes() workspaceConfigHashCtx.Mixin(options->mAllocStackCount); workspaceConfigHashCtx.Mixin(options->mExtraResolveChecks); + workspaceConfigHashCtx.Mixin(options->mMaxSplatRegs); workspaceConfigHashCtx.MixinStr(options->mMallocLinkName); workspaceConfigHashCtx.MixinStr(options->mFreeLinkName); @@ -1842,6 +1849,11 @@ void BfContext::UpdateRevisedTypes() workspaceConfigHashCtx.Mixin(typeOptions.mAllocStackTraceDepth); } +// for (auto project : mSystem->mProjects) +// { +// workspaceConfigHashCtx.MixinStr(project->mName); +// } + Val128 workspaceConfigHash = workspaceConfigHashCtx.Finish128(); mSystem->mWorkspaceConfigChanged = mSystem->mWorkspaceConfigHash != workspaceConfigHash; @@ -1852,8 +1864,7 @@ void BfContext::UpdateRevisedTypes() mSystem->mMergedTypeOptions.Clear(); mSystem->mWorkspaceConfigHash = workspaceConfigHash; } - - AutoCrit autoCrit(mSystem->mDataLock); + for (auto project : mSystem->mProjects) { HashContext buildConfigHashCtx; @@ -1861,11 +1872,14 @@ void BfContext::UpdateRevisedTypes() if (!mCompiler->mIsResolveOnly) { - auto& codeGenOptions = project->mCodeGenOptions; + auto& codeGenOptions = project->mCodeGenOptions; + buildConfigHashCtx.Mixin(project->mAlwaysIncludeAll); + buildConfigHashCtx.Mixin(project->mSingleModule); + bool isTestConfig = project->mTargetType == BfTargetType_BeefTest; buildConfigHashCtx.Mixin(isTestConfig); - + buildConfigHashCtx.Mixin(codeGenOptions.mOptLevel); buildConfigHashCtx.Mixin(codeGenOptions.mSizeLevel); buildConfigHashCtx.Mixin(codeGenOptions.mUseCFLAA); @@ -1888,6 +1902,7 @@ void BfContext::UpdateRevisedTypes() buildConfigHashCtx.Mixin(codeGenOptions.mRunSLPAfterLoopVectorization); buildConfigHashCtx.Mixin(codeGenOptions.mUseGVNAfterVectorization); } + buildConfigHashCtx.Mixin(project->mDisabled); buildConfigHashCtx.Mixin(project->mTargetType); for (auto dep : project->mDependencies) @@ -2226,6 +2241,12 @@ String BfContext::GenerateModuleName(BfTypeInstance* typeInst) name.RemoveToEnd(80); name += "__"; } + for (int i = 0; i < (int)name.length(); i++) + { + char c = name[i]; + if (c == '@') + name[i] = '_'; + } String tryName = name; for (int i = 2; true; i++) diff --git a/IDEHelper/Compiler/BfIRBuilder.cpp b/IDEHelper/Compiler/BfIRBuilder.cpp index 96e54103e..88e8c9229 100644 --- a/IDEHelper/Compiler/BfIRBuilder.cpp +++ b/IDEHelper/Compiler/BfIRBuilder.cpp @@ -2110,7 +2110,7 @@ void BfIRBuilder::CreateTypeDeclaration(BfType* type, bool forceDefine) String prefix = typeDef->mProject->mName + "."; StringT<128> mangledName; mangledName += prefix; - BfMangler::Mangle(mangledName, mModule->mCompiler->GetMangleKind(), typeInstance); + BfMangler::Mangle(mangledName, mModule->mCompiler->GetMangleKind(), typeInstance, typeInstance->mModule); BfIRType irStructType = CreateStructType(mangledName); if (type->IsObjectOrInterface()) { @@ -4748,7 +4748,7 @@ BfIRValue BfIRBuilder::DbgLifetimeEnd(BfIRMDNode varInfo) } void BfIRBuilder::DbgCreateGlobalVariable(BfIRMDNode context, const StringImpl& name, const StringImpl& linkageName, BfIRMDNode file, int lineNumber, BfIRMDNode type, bool isLocalToUnit, BfIRValue val, BfIRMDNode decl) -{ +{ WriteCmd(BfIRCmd_DbgCreateGlobalVariable, context, name, linkageName, file, lineNumber, type, isLocalToUnit, val, decl); NEW_CMD_INSERTED; } diff --git a/IDEHelper/Compiler/BfIRCodeGen.cpp b/IDEHelper/Compiler/BfIRCodeGen.cpp index 31e5e75af..cf2b248fe 100644 --- a/IDEHelper/Compiler/BfIRCodeGen.cpp +++ b/IDEHelper/Compiler/BfIRCodeGen.cpp @@ -4009,9 +4009,44 @@ bool BfIRCodeGen::WriteObjectFile(const StringImpl& outFileName, const BfCodeGen llvm::Optional relocModel; llvm::CodeModel::Model cmModel = llvm::CodeModel::Small; + switch (codeGenOptions.mRelocType) + { + case BfRelocType_Static: + relocModel = llvm::Reloc::Model::DynamicNoPIC; + break; + case BfRelocType_PIC: + relocModel = llvm::Reloc::Model::PIC_; + break; + case BfRelocType_DynamicNoPIC: + relocModel = llvm::Reloc::Model::DynamicNoPIC; + break; + case BfRelocType_ROPI: + relocModel = llvm::Reloc::Model::ROPI; + break; + case BfRelocType_RWPI: + relocModel = llvm::Reloc::Model::RWPI; + break; + case BfRelocType_ROPI_RWPI: + relocModel = llvm::Reloc::Model::ROPI_RWPI; + break; + } + + switch (codeGenOptions.mPICLevel) + { + case BfPICLevel_Not: + mLLVMModule->setPICLevel(llvm::PICLevel::Level::NotPIC); + break; + case BfPICLevel_Small: + mLLVMModule->setPICLevel(llvm::PICLevel::Level::SmallPIC); + break; + case BfPICLevel_Big: + mLLVMModule->setPICLevel(llvm::PICLevel::Level::BigPIC); + break; + } + std::unique_ptr target( theTarget->createTargetMachine(theTriple.getTriple(), cpuName.c_str(), featuresStr.c_str(), - Options, relocModel, cmModel, optLvl)); + Options, relocModel, cmModel, optLvl)); std::error_code EC; llvm::sys::fs::OpenFlags OpenFlags = llvm::sys::fs::F_None; @@ -4188,6 +4223,11 @@ void BfIRCodeGen::StaticInit() LLVMInitializeX86AsmParser(); LLVMInitializeX86Disassembler(); + LLVMInitializeARMTargetInfo(); + LLVMInitializeARMTarget(); + LLVMInitializeARMTargetMC(); + LLVMInitializeARMAsmPrinter(); + LLVMInitializeAArch64TargetInfo(); LLVMInitializeAArch64Target(); LLVMInitializeAArch64TargetMC(); diff --git a/IDEHelper/Compiler/BfMangler.cpp b/IDEHelper/Compiler/BfMangler.cpp index 35f2afe47..e79dac336 100644 --- a/IDEHelper/Compiler/BfMangler.cpp +++ b/IDEHelper/Compiler/BfMangler.cpp @@ -56,13 +56,10 @@ BfTypeCode BfGNUMangler::GetPrimTypeAt(MangleContext& mangleContext, StringImpl& case 't': return BfTypeCode_UInt16; case 'i': return BfTypeCode_Int32; case 'j': return BfTypeCode_UInt32; -#if __SIZEOF_LONG__ == 8 case 'l': return BfTypeCode_Int64; case 'm': return BfTypeCode_UInt64; -#else case 'x': return BfTypeCode_Int64; case 'y': return BfTypeCode_UInt64; -#endif case 'u': if (name[strIdx + 1] == '3') return BfTypeCode_IntPtr; @@ -234,9 +231,9 @@ void BfGNUMangler::FindOrCreateNameSub(MangleContext& mangleContext, StringImpl& else name += "4"; if (genericParamType->mGenericParamKind == BfGenericParamKind_Method) - name += "@M"; + name += "`M"; else - name += "@T"; + name += "`T"; itoa(genericParamType->mGenericParamIdx, str, 10); name += str; } @@ -274,7 +271,7 @@ void BfGNUMangler::FindOrCreateNameSub(MangleContext& mangleContext, StringImpl& } void BfGNUMangler::MangleTypeInst(MangleContext& mangleContext, StringImpl& name, BfTypeInstance* typeInst, BfTypeInstance* postfixTypeInstance, bool* isEndOpen) -{ +{ static int sCallCount = 0; sCallCount++; @@ -289,7 +286,7 @@ void BfGNUMangler::MangleTypeInst(MangleContext& mangleContext, StringImpl& name BfFieldDef* fieldDef = fieldInstance->GetFieldDef(); String fieldName = fieldDef->mName; if ((fieldName[0] < '0') || (fieldName[0] > '9')) - name += StrFormat("U%d@%s", fieldName.length() + 1, fieldName.c_str()); + name += StrFormat("U%d`%s", fieldName.length() + 1, fieldName.c_str()); Mangle(mangleContext, name, fieldInstance->mResolvedType, postfixTypeInstance); } name += "E"; @@ -444,25 +441,25 @@ void BfGNUMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType name += "i"; return; case BfTypeCode_UInt32: name += "j"; return; -#if __SIZEOF_LONG__ == 8 - case BfTypeCode_Int64: - name += "l"; return; - case BfTypeCode_UInt64: - name += "m"; return; -#else case BfTypeCode_Int64: - name += "x"; return; + if (mangleContext.mModule->mCompiler->mOptions.mCLongSize == 8) + name += "l"; + else + name += "x"; + return; case BfTypeCode_UInt64: - name += "y"; return; -#endif + if (mangleContext.mModule->mCompiler->mOptions.mCLongSize == 8) + name += "m"; + else + name += "y"; + return; case BfTypeCode_UIntPtr: if ((mangleContext.mCCompat) || (mangleContext.mInArgs)) { -#if __SIZEOF_LONG__ == 8 - name += (primType->mSize == 8) ? "m" : "j"; -#else - name += (primType->mSize == 8) ? "y" : "j"; -#endif + if (mangleContext.mModule->mCompiler->mOptions.mCLongSize == 8) + name += (primType->mSize == 8) ? "m" : "j"; + else + name += (primType->mSize == 8) ? "y" : "j"; return; } name += "u4uint"; @@ -470,11 +467,10 @@ void BfGNUMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType case BfTypeCode_IntPtr: if ((mangleContext.mCCompat) || (mangleContext.mInArgs)) { -#if __SIZEOF_LONG__ == 8 - name += (primType->mSize == 8) ? "l" : "i"; -#else - name += (primType->mSize == 8) ? "x" : "i"; -#endif + if (mangleContext.mModule->mCompiler->mOptions.mCLongSize == 8) + name += (primType->mSize == 8) ? "l" : "i"; + else + name += (primType->mSize == 8) ? "x" : "i"; return; } name += "u3int"; @@ -635,7 +631,7 @@ void BfGNUMangler::Mangle(MangleContext& mangleContext, StringImpl& name, BfType } name += strP; - name += '@'; + name += '`'; } } else @@ -834,7 +830,7 @@ String BfGNUMangler::Mangle(BfMethodInstance* methodInst) { if (methodInst->mMangleWithIdx) { - methodName += StrFormat("@%d", methodInst->mMethodDef->mIdx); + methodName += StrFormat("`%d", methodInst->mMethodDef->mIdx); mangledMethodIdx = true; } @@ -842,9 +838,9 @@ String BfGNUMangler::Mangle(BfMethodInstance* methodInst) } if (methodDef->mCheckedKind == BfCheckedKind_Checked) - name += "@CHK"; + name += "`CHK"; else if (methodDef->mCheckedKind == BfCheckedKind_Unchecked) - name += "@UCHK"; + name += "`UCHK"; if ((methodInst->mMethodDef->mDeclaringType->mPartialIdx != -1) && (!methodInst->mIsForeignMethodDef)) { @@ -877,14 +873,14 @@ String BfGNUMangler::Mangle(BfMethodInstance* methodInst) if ((methodInst->mMangleWithIdx) && (!mangledMethodIdx)) { - methodName += StrFormat("@%d", methodInst->mMethodDef->mIdx); + methodName += StrFormat("`%d", methodInst->mMethodDef->mIdx); } // if ((prefixLen) && (methodInst->mMethodInstanceGroup->mOwner->mTypeDef->IsGlobalsContainer()) && (methodInst->mMethodDef->mMethodDeclaration == NULL)) { - methodName += '@'; + methodName += '`'; methodName += methodInst->mMethodInstanceGroup->mOwner->mTypeDef->mProject->mName; } diff --git a/IDEHelper/Compiler/BfModule.cpp b/IDEHelper/Compiler/BfModule.cpp index 2e437627e..59a9bce4b 100644 --- a/IDEHelper/Compiler/BfModule.cpp +++ b/IDEHelper/Compiler/BfModule.cpp @@ -4319,12 +4319,12 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin { BfMangler::MangleStaticFieldName(typeDataName, mCompiler->GetMangleKind(), typeInstance, "sBfTypeData"); if (typeInstance->mTypeDef->IsGlobalsContainer()) - typeDataName += "@" + typeInstance->mTypeDef->mProject->mName; + typeDataName += "`G`" + typeInstance->mTypeDef->mProject->mName; } else { typeDataName += "sBfTypeData."; - BfMangler::Mangle(typeDataName, mCompiler->GetMangleKind(), type); + BfMangler::Mangle(typeDataName, mCompiler->GetMangleKind(), type, mContext->mScratchModule); } int typeCode = BfTypeCode_None; @@ -4460,7 +4460,7 @@ BfIRValue BfModule::CreateTypeData(BfType* type, Dictionary& usedStrin BfTypeDef* typeDef = typeInstance->mTypeDef; StringT<128> mangledName; - BfMangler::Mangle(mangledName, mCompiler->GetMangleKind(), typeInstance); + BfMangler::Mangle(mangledName, mCompiler->GetMangleKind(), typeInstance, typeInstance->mModule); for (int methodIdx = 0; methodIdx < (int)typeDef->mMethods.size(); methodIdx++) { @@ -13619,8 +13619,8 @@ void BfModule::CreateDllImportMethod() BfIRCallingConv BfModule::GetCallingConvention(BfTypeInstance* typeInst, BfMethodDef* methodDef) { - if (mSystem->mPtrSize == 8) - return BfIRCallingConv_CDecl; + if ((mCompiler->mOptions.mMachineType != BfMachineType_x86) || (mCompiler->mOptions.mPlatformType != BfPlatformType_Windows)) + return BfIRCallingConv_CDecl; if (methodDef->mCallingConvention == BfCallingConvention_Stdcall) return BfIRCallingConv_StdCall; if ((!methodDef->mIsStatic) && (!typeInst->IsValuelessType()) && diff --git a/IDEHelper/Compiler/BfSystem.cpp b/IDEHelper/Compiler/BfSystem.cpp index f4399c89e..dd68f0c83 100644 --- a/IDEHelper/Compiler/BfSystem.cpp +++ b/IDEHelper/Compiler/BfSystem.cpp @@ -3592,8 +3592,8 @@ BF_EXPORT void BF_CALLTYPE BfProject_SetDisabled(BfProject* bfProject, bool disa bfProject->mDisabled = disabled; } -BF_EXPORT void BF_CALLTYPE BfProject_SetOptions(BfProject* bfProject, int targetType, const char* startupObject, const char* preprocessorMacros, - int optLevel, int ltoType, BfProjectFlags flags) +BF_EXPORT void BF_CALLTYPE BfProject_SetOptions(BfProject* bfProject, int targetType, const char* startupObject, const char* preprocessorMacros, + int optLevel, int ltoType, int relocType, int picLevel, BfProjectFlags flags) { bfProject->mTargetType = (BfTargetType)targetType; bfProject->mStartupObject = startupObject; @@ -3601,6 +3601,8 @@ BF_EXPORT void BF_CALLTYPE BfProject_SetOptions(BfProject* bfProject, int target BfCodeGenOptions codeGenOptions; codeGenOptions.mOptLevel = (BfOptLevel)optLevel; codeGenOptions.mLTOType = (BfLTOType)ltoType; + codeGenOptions.mRelocType = (BfRelocType)relocType; + codeGenOptions.mPICLevel = (BfPICLevel)picLevel; codeGenOptions.mMergeFunctions = (flags & BfProjectFlags_MergeFunctions) != 0; codeGenOptions.mLoadCombine = (flags & BfProjectFlags_CombineLoads) != 0; codeGenOptions.mLoopVectorize = (flags & BfProjectFlags_VectorizeLoops) != 0; diff --git a/IDEHelper/Compiler/BfSystem.h b/IDEHelper/Compiler/BfSystem.h index 2676aa3fb..493daf1ee 100644 --- a/IDEHelper/Compiler/BfSystem.h +++ b/IDEHelper/Compiler/BfSystem.h @@ -204,11 +204,22 @@ enum BfCustomAttributeFlags BfCustomAttributeFlags_AlwaysIncludeTarget = 8 }; +enum BfPlatformType +{ + BfPlatformType_Unknown, + BfPlatformType_Windows, + BfPlatformType_Linux, + BfPlatformType_macOS, + BfPlatformType_iOS, + BfPlatformType_Android, +}; + enum BfMachineType { BfMachineType_Unknown, BfMachineType_x86, BfMachineType_x64, + BfMachineType_ARM, BfMachineType_AArch64 }; @@ -265,6 +276,25 @@ enum BfCFLAAType BfCFLAAType_Both }; +enum BfRelocType +{ + BfRelocType_NotSet, + BfRelocType_Static, + BfRelocType_PIC, + BfRelocType_DynamicNoPIC, + BfRelocType_ROPI, + BfRelocType_RWPI, + BfRelocType_ROPI_RWPI +}; + +enum BfPICLevel +{ + BfPICLevel_NotSet, + BfPICLevel_Not, + BfPICLevel_Small, + BfPICLevel_Big +}; + struct BfCodeGenOptions { bool mIsHotCompile; @@ -277,6 +307,8 @@ struct BfCodeGenOptions int16 mVirtualMethodOfs; int16 mDynSlotOfs; + BfRelocType mRelocType; + BfPICLevel mPICLevel; BfSIMDSetting mSIMDSetting; BfOptLevel mOptLevel; BfLTOType mLTOType; @@ -327,7 +359,9 @@ struct BfCodeGenOptions mWriteLLVMIR = false; mVirtualMethodOfs = 0; mDynSlotOfs = 0; - + + mRelocType = BfRelocType_NotSet; + mPICLevel = BfPICLevel_NotSet; mSIMDSetting = BfSIMDSetting_None; mOptLevel = BfOptLevel_O0; mLTOType = BfLTOType_None; @@ -378,6 +412,8 @@ struct BfCodeGenOptions hashCtx.Mixin(mVirtualMethodOfs); hashCtx.Mixin(mDynSlotOfs); + hashCtx.Mixin(mRelocType); + hashCtx.Mixin(mPICLevel); hashCtx.Mixin(mSIMDSetting); hashCtx.Mixin(mOptLevel); hashCtx.Mixin(mLTOType); @@ -950,7 +986,9 @@ enum BfTargetType BfTargetType_CustomBuild, BfTargetType_C_ConsoleApplication, BfTargetType_C_WindowsApplication, - BfTargetType_BeefTest + BfTargetType_BeefTest, + BfTargetType_BeefApplication_StaticLib, + BfTargetType_BeefApplication_DynamicLib }; enum BfProjectFlags diff --git a/IDEHelper/IDEHelper.vcxproj b/IDEHelper/IDEHelper.vcxproj index 3b317e715..bf5f4eb4b 100644 --- a/IDEHelper/IDEHelper.vcxproj +++ b/IDEHelper/IDEHelper.vcxproj @@ -171,7 +171,7 @@ Windows DebugFull $(SolutionDir)\IDE\dist\$(TargetName).dll - rpcrt4.lib;cabinet.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;libcurl_a.lib;wininet.lib;LLVMMCDisassembler.lib;LLVMSupport.lib;LLVMMC.lib;LLVMObject.lib;LLVMCore.lib;LLVMBitReader.lib;LLVMAsmParser.lib;LLVMMCParser.lib;LLVMCodeGen.lib;LLVMTarget.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMSelectionDAG.lib;LLVMProfileData.lib;LLVMTransformUtils.lib;LLVMAnalysis.lib;LLVMAsmPrinter.lib;LLVMBitWriter.lib;LLVMVectorize.lib;LLVMipo.lib;LLVMInstrumentation.lib;LLVMDebugInfoDWARF.lib;LLVMDebugInfoPDB.lib;LLVMDebugInfoCodeView.lib;LLVMGlobalISel.lib;LLVMBinaryFormat.lib;LLVMLTO.lib;LLVMPasses.lib;LLVMLinker.lib;LLVMIRReader.lib;LLVMDemangle.lib;LLVMAggressiveInstCombine.lib;LLVMX86Info.lib;LLVMX86Utils.lib;LLVMX86AsmPrinter.lib;LLVMX86Desc.lib;LLVMX86CodeGen.lib;LLVMX86AsmParser.lib;LLVMX86Disassembler.lib;LLVMAArch64Info.lib;LLVMAArch64Utils.lib;LLVMAArch64AsmPrinter.lib;LLVMAArch64Desc.lib;LLVMAArch64CodeGen.lib;LLVMAArch64AsmParser.lib;LLVMAArch64Disassembler.lib;%(AdditionalDependencies) + rpcrt4.lib;cabinet.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;libcurl_a.lib;wininet.lib;LLVMMCDisassembler.lib;LLVMSupport.lib;LLVMMC.lib;LLVMObject.lib;LLVMCore.lib;LLVMBitReader.lib;LLVMAsmParser.lib;LLVMMCParser.lib;LLVMCodeGen.lib;LLVMTarget.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMSelectionDAG.lib;LLVMProfileData.lib;LLVMTransformUtils.lib;LLVMAnalysis.lib;LLVMAsmPrinter.lib;LLVMBitWriter.lib;LLVMVectorize.lib;LLVMipo.lib;LLVMInstrumentation.lib;LLVMDebugInfoDWARF.lib;LLVMDebugInfoPDB.lib;LLVMDebugInfoCodeView.lib;LLVMGlobalISel.lib;LLVMBinaryFormat.lib;LLVMLTO.lib;LLVMPasses.lib;LLVMLinker.lib;LLVMIRReader.lib;LLVMDemangle.lib;LLVMAggressiveInstCombine.lib;LLVMX86Info.lib;LLVMX86Utils.lib;LLVMX86AsmPrinter.lib;LLVMX86Desc.lib;LLVMX86CodeGen.lib;LLVMX86AsmParser.lib;LLVMX86Disassembler.lib;LLVMAArch64Info.lib;LLVMAArch64Utils.lib;LLVMAArch64AsmPrinter.lib;LLVMAArch64Desc.lib;LLVMAArch64CodeGen.lib;LLVMAArch64AsmParser.lib;LLVMAArch64Disassembler.lib;LLVMARMInfo.lib;LLVMARMUtils.lib;LLVMARMAsmPrinter.lib;LLVMARMDesc.lib;LLVMARMCodeGen.lib;LLVMARMAsmParser.lib;LLVMARMDisassembler.lib;%(AdditionalDependencies) ..\extern\llvm_win64_8_0_1\Debug\lib; ..\extern\curl\builds\libcurl-vc15-x64-release-static-zlib-static-ipv6-sspi-winssl\lib;..\extern\curl\deps\lib;..\extern\jemalloc_win\x64\debug false $(SolutionDir)\IDE\dist\$(TargetName).lib @@ -230,7 +230,7 @@ true $(SolutionDir)\IDE\dist\$(TargetName).dll ..\extern\llvm_win64_8_0_1\Release\lib; ..\extern\curl\builds\libcurl-vc15-x64-release-static-zlib-static-ipv6-sspi-winssl\lib;..\extern\curl\deps\lib;..\extern\jemalloc_win\x64\release - rpcrt4.lib;cabinet.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;libcurl_a.lib;wininet.lib;LLVMMCDisassembler.lib;LLVMSupport.lib;LLVMMC.lib;LLVMObject.lib;LLVMCore.lib;LLVMBitReader.lib;LLVMAsmParser.lib;LLVMMCParser.lib;LLVMCodeGen.lib;LLVMTarget.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMSelectionDAG.lib;LLVMProfileData.lib;LLVMTransformUtils.lib;LLVMAnalysis.lib;LLVMAsmPrinter.lib;LLVMBitWriter.lib;LLVMVectorize.lib;LLVMipo.lib;LLVMInstrumentation.lib;LLVMDebugInfoDWARF.lib;LLVMDebugInfoPDB.lib;LLVMDebugInfoCodeView.lib;LLVMGlobalISel.lib;LLVMBinaryFormat.lib;LLVMLTO.lib;LLVMPasses.lib;LLVMLinker.lib;LLVMIRReader.lib;LLVMDemangle.lib;LLVMAggressiveInstCombine.lib;LLVMX86Info.lib;LLVMX86Utils.lib;LLVMX86AsmPrinter.lib;LLVMX86Desc.lib;LLVMX86CodeGen.lib;LLVMX86AsmParser.lib;LLVMX86Disassembler.lib;LLVMAArch64Info.lib;LLVMAArch64Utils.lib;LLVMAArch64AsmPrinter.lib;LLVMAArch64Desc.lib;LLVMAArch64CodeGen.lib;LLVMAArch64AsmParser.lib;LLVMAArch64Disassembler.lib;%(AdditionalDependencies) + rpcrt4.lib;cabinet.lib;winmm.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;libcurl_a.lib;wininet.lib;LLVMMCDisassembler.lib;LLVMSupport.lib;LLVMMC.lib;LLVMObject.lib;LLVMCore.lib;LLVMBitReader.lib;LLVMAsmParser.lib;LLVMMCParser.lib;LLVMCodeGen.lib;LLVMTarget.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMSelectionDAG.lib;LLVMProfileData.lib;LLVMTransformUtils.lib;LLVMAnalysis.lib;LLVMAsmPrinter.lib;LLVMBitWriter.lib;LLVMVectorize.lib;LLVMipo.lib;LLVMInstrumentation.lib;LLVMDebugInfoDWARF.lib;LLVMDebugInfoPDB.lib;LLVMDebugInfoCodeView.lib;LLVMGlobalISel.lib;LLVMBinaryFormat.lib;LLVMLTO.lib;LLVMPasses.lib;LLVMLinker.lib;LLVMIRReader.lib;LLVMDemangle.lib;LLVMAggressiveInstCombine.lib;LLVMX86Info.lib;LLVMX86Utils.lib;LLVMX86AsmPrinter.lib;LLVMX86Desc.lib;LLVMX86CodeGen.lib;LLVMX86AsmParser.lib;LLVMX86Disassembler.lib;LLVMAArch64Info.lib;LLVMAArch64Utils.lib;LLVMAArch64AsmPrinter.lib;LLVMAArch64Desc.lib;LLVMAArch64CodeGen.lib;LLVMAArch64AsmParser.lib;LLVMAArch64Disassembler.lib;LLVMARMInfo.lib;LLVMARMUtils.lib;LLVMARMAsmPrinter.lib;LLVMARMDesc.lib;LLVMARMCodeGen.lib;LLVMARMAsmParser.lib;LLVMARMDisassembler.lib;%(AdditionalDependencies) false true $(SolutionDir)\IDE\dist\$(TargetName).lib diff --git a/bin/build_android.bat b/bin/build_android.bat new file mode 100644 index 000000000..0722af468 --- /dev/null +++ b/bin/build_android.bat @@ -0,0 +1,210 @@ +PUSHD %~dp0..\ + +SET NDK=C:\Users\Brian\AppData\Local\Android\Sdk\ndk\20.0.5594570 +SET NINJA=C:\Users\Brian\AppData\Local\Android\Sdk\cmake\3.10.2.4988404\bin\ninja.exe +@REM SET NDK=C:\NVPACK\android-ndk-r14b + +@REM i686-none-linux-android16 +@REM i686-linux-android armv7-none-linux-androideabi16 + +cd builds +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR + +@IF EXIST android_x86 GOTO DO_BUILD + +mkdir android_x86_d +cd android_x86_d +cmake -GNinja ^ + -DANDROID_ABI:UNINITIALIZED=x86 ^ + -DANDROID_NDK=%NDK% ^ + -DANDROID_PLATFORM=android-16 ^ + -DCMAKE_ANDROID_ARCH_ABI=x86 ^ + -DCMAKE_ANDROID_NDK=%NDK% ^ + -DCMAKE_SYSTEM_NAME=Android ^ + -DCMAKE_SYSTEM_VERSION=16 ^ + -DCMAKE_TOOLCHAIN_FILE=%NDK%\build\cmake\android.toolchain.cmake ^ + -DCMAKE_MAKE_PROGRAM=%NINJA% ^ + -DCMAKE_BUILD_TYPE=Debug ^ + ..\..\BeefRT +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +mkdir android_x86 +cd android_x86 +cmake -GNinja ^ + -DANDROID_ABI:UNINITIALIZED=x86 ^ + -DANDROID_NDK=%NDK% ^ + -DANDROID_PLATFORM=android-16 ^ + -DCMAKE_ANDROID_ARCH_ABI=x86 ^ + -DCMAKE_ANDROID_NDK=%NDK% ^ + -DCMAKE_SYSTEM_NAME=Android ^ + -DCMAKE_SYSTEM_VERSION=16 ^ + -DCMAKE_TOOLCHAIN_FILE=%NDK%\build\cmake\android.toolchain.cmake ^ + -DCMAKE_MAKE_PROGRAM=%NINJA% ^ + -DCMAKE_BUILD_TYPE=Release ^ + ..\..\BeefRT +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +mkdir android_x86_64_d +cd android_x86_64_d +cmake -GNinja ^ + -DANDROID_ABI:UNINITIALIZED=x86_64 ^ + -DANDROID_NDK=%NDK% ^ + -DANDROID_PLATFORM=android-16 ^ + -DCMAKE_ANDROID_ARCH_ABI=x86_64 ^ + -DCMAKE_ANDROID_NDK=%NDK% ^ + -DCMAKE_SYSTEM_NAME=Android ^ + -DCMAKE_SYSTEM_VERSION=16 ^ + -DCMAKE_TOOLCHAIN_FILE=%NDK%\build\cmake\android.toolchain.cmake ^ + -DCMAKE_MAKE_PROGRAM=%NINJA% ^ + -DCMAKE_BUILD_TYPE=Debug ^ + ..\..\BeefRT +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +mkdir android_x86_64 +cd android_x86_64 +cmake -GNinja ^ + -DANDROID_ABI:UNINITIALIZED=x86_64 ^ + -DANDROID_NDK=%NDK% ^ + -DANDROID_PLATFORM=android-16 ^ + -DCMAKE_ANDROID_ARCH_ABI=x86_64 ^ + -DCMAKE_ANDROID_NDK=%NDK% ^ + -DCMAKE_SYSTEM_NAME=Android ^ + -DCMAKE_SYSTEM_VERSION=16 ^ + -DCMAKE_TOOLCHAIN_FILE=%NDK%\build\cmake\android.toolchain.cmake ^ + -DCMAKE_MAKE_PROGRAM=%NINJA% ^ + -DCMAKE_BUILD_TYPE=Release ^ + ..\..\BeefRT +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +mkdir android_arm_d +cd android_arm_d +cmake -GNinja ^ + -DANDROID_ABI:UNINITIALIZED=armeabi-v7a ^ + -DANDROID_NDK=%NDK% ^ + -DANDROID_PLATFORM=android-16 ^ + -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a ^ + -DCMAKE_ANDROID_NDK=%NDK% ^ + -DCMAKE_SYSTEM_NAME=Android ^ + -DCMAKE_SYSTEM_VERSION=16 ^ + -DCMAKE_TOOLCHAIN_FILE=%NDK%\build\cmake\android.toolchain.cmake ^ + -DCMAKE_MAKE_PROGRAM=%NINJA% ^ + -DCMAKE_BUILD_TYPE=Debug ^ + ..\..\BeefRT +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +mkdir android_arm +cd android_arm +cmake -GNinja ^ + -DANDROID_ABI:UNINITIALIZED=armeabi-v7a ^ + -DANDROID_NDK=%NDK% ^ + -DANDROID_PLATFORM=android-16 ^ + -DCMAKE_ANDROID_ARCH_ABI=armeabi-v7a ^ + -DCMAKE_ANDROID_NDK=%NDK% ^ + -DCMAKE_SYSTEM_NAME=Android ^ + -DCMAKE_SYSTEM_VERSION=16 ^ + -DCMAKE_TOOLCHAIN_FILE=%NDK%\build\cmake\android.toolchain.cmake ^ + -DCMAKE_MAKE_PROGRAM=%NINJA% ^ + -DCMAKE_BUILD_TYPE=Release ^ + ..\..\BeefRT +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +mkdir android_arm64_d +cd android_arm64_d +cmake -GNinja ^ + -DANDROID_ABI:UNINITIALIZED=arm64-v8a ^ + -DANDROID_NDK=%NDK% ^ + -DANDROID_PLATFORM=android-21 ^ + -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a ^ + -DCMAKE_ANDROID_NDK=%NDK% ^ + -DCMAKE_SYSTEM_NAME=Android ^ + -DCMAKE_SYSTEM_VERSION=21 ^ + -DCMAKE_TOOLCHAIN_FILE=%NDK%\build\cmake\android.toolchain.cmake ^ + -DCMAKE_MAKE_PROGRAM=%NINJA% ^ + -DCMAKE_BUILD_TYPE=Debug ^ + ..\..\BeefRT +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +mkdir android_arm64 +cd android_arm64 +cmake -GNinja ^ + -DANDROID_ABI:UNINITIALIZED=arm64-v8a ^ + -DANDROID_NDK=%NDK% ^ + -DANDROID_PLATFORM=android-21 ^ + -DCMAKE_ANDROID_ARCH_ABI=arm64-v8a ^ + -DCMAKE_ANDROID_NDK=%NDK% ^ + -DCMAKE_SYSTEM_NAME=Android ^ + -DCMAKE_SYSTEM_VERSION=21 ^ + -DCMAKE_TOOLCHAIN_FILE=%NDK%\build\cmake\android.toolchain.cmake ^ + -DCMAKE_MAKE_PROGRAM=%NINJA% ^ + -DCMAKE_BUILD_TYPE=Release ^ + ..\..\BeefRT +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +:DO_BUILD + +cd android_x86_d +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cmake --build . +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +cd android_x86 +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cmake --build . +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +cd android_x86_64_d +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cmake --build . +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +cd android_x86_64 +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cmake --build . +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +cd android_arm_d +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cmake --build . +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +cd android_arm +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cmake --build . +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +cd android_arm64_d +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cmake --build . +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +cd android_arm64 +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cmake --build . +@IF %ERRORLEVEL% NEQ 0 GOTO HADERROR +cd .. + +:SUCCESS +@ECHO SUCCESS! +@POPD +@EXIT /b 0 + +:HADERROR +@ECHO =================FAILED================= +@POPD +@EXIT /b %ERRORLEVEL% \ No newline at end of file