From ec02055dd9a7df2ca599d8abbe7681060a1aa068 Mon Sep 17 00:00:00 2001 From: chuggafan Date: Fri, 3 Jan 2025 23:59:02 -0500 Subject: [PATCH] Fix prototype code. --- src/omake/MakeMain.cpp | 15 +- src/omake/Maker.cpp | 2 +- src/omake/Variable.cpp | 18 +- src/omake/os.cpp | 220 +++++++++++++++--- .../os_specific/Linux/Linux_Jobserver.cpp | 22 +- src/omake/semaphores.h | 55 ++--- src/util/ToolChain.cpp | 2 +- src/util/Utils.cpp | 25 +- 8 files changed, 261 insertions(+), 98 deletions(-) diff --git a/src/omake/MakeMain.cpp b/src/omake/MakeMain.cpp index 06abcf19a..36a858380 100644 --- a/src/omake/MakeMain.cpp +++ b/src/omake/MakeMain.cpp @@ -306,11 +306,18 @@ bool MakeMain::LoadJobArgs() } void MakeMain::LoadEnvironment() { -#ifdef TARGET_OS_WINDOWS - char** env = environ; -#else - char** env = 0; +// https://www.man7.org/linux/man-pages/man7/environ.7.html +/* + *Historically and by standard, environ must be declared in the + *user program. However, as a (nonstandard) programmer + *convenience, environ is declared in the header file if + *the _GNU_SOURCE feature test macro is defined (see + *feature_test_macros(7)). + */ +#ifndef TARGET_OS_WINDOWS + extern char** environ; #endif + char** env = environ; Variable::Origin origin; if (environOverride.GetValue()) origin = Variable::o_environ_override; diff --git a/src/omake/Maker.cpp b/src/omake/Maker.cpp index 9f78c1fa5..b39442eb6 100644 --- a/src/omake/Maker.cpp +++ b/src/omake/Maker.cpp @@ -60,7 +60,7 @@ Maker::Maker(bool Silent, bool DisplayOnly, bool IgnoreResults, bool Touch, Outp Variable* v = VariableContainer::Instance()->Lookup("SHELL"); std::string shtest = v->GetValue(); std::transform(shtest.begin(), shtest.end(), shtest.begin(), ::toupper); - OS::SetSHEXE(shtest.find("SH.EXE") != std::string::npos || shtest.find("BASH.EXE") != std::string::npos); + OS::SetSHEXE(shtest.find("sh") != std::string::npos); } Maker::~Maker() {} void Maker::SetFirstGoal(const std::string& name) diff --git a/src/omake/Variable.cpp b/src/omake/Variable.cpp index 30910a8b5..5e6ee0191 100644 --- a/src/omake/Variable.cpp +++ b/src/omake/Variable.cpp @@ -1,26 +1,26 @@ /* Software License Agreement - * + * * Copyright(C) 1994-2024 David Lindauer, (LADSoft) - * + * * This file is part of the Orange C Compiler package. - * + * * The Orange C Compiler package is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * The Orange C Compiler package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with Orange C. If not, see . - * + * * contact information: * email: TouchStone222@runbox.com - * - * + * + * */ #include "Variable.h" @@ -85,6 +85,8 @@ Variable* VariableContainer::Lookup(const std::string& name) } void VariableContainer::operator+(Variable* variable) { + if (!variable) + return; std::unique_ptr temp(variable); if (variable->GetName().find_first_of('%') != std::string::npos) { diff --git a/src/omake/os.cpp b/src/omake/os.cpp index 76fbef2ed..1c49513e1 100644 --- a/src/omake/os.cpp +++ b/src/omake/os.cpp @@ -1,34 +1,44 @@ /* Software License Agreement - * + * * Copyright(C) 1994-2024 David Lindauer, (LADSoft) - * + * * This file is part of the Orange C Compiler package. - * + * * The Orange C Compiler package is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * The Orange C Compiler package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with Orange C. If not, see . - * + * * contact information: * email: TouchStone222@runbox.com - * - * + * + * */ #define _CRT_SECURE_NO_WARNINGS - +#ifdef __unix__ +# define HAVE_UNISTD_H +#endif #ifdef HAVE_UNISTD_H +# define _POSIX_C_SOURCE 200809L +# include +# include +# include +# include # include # define _SH_DENYNO 0 # include +# include +# include +# include #else # include # include @@ -68,7 +78,7 @@ #include #include #include "JobServer.h" -//#define DEBUG +// #define DEBUG static std::mutex processIdMutex; // This is required because GetFullPathName and SetCurrentDirectory and GetCurrentDirectory are // all non-safe in multithreaded environments, in order to make this safe, we *MUST* lower ourselves into making these a mutex-gated @@ -82,20 +92,26 @@ std::string OS::jobFile; std::shared_ptr OS::localJobServer = nullptr; #ifdef TARGET_OS_WINDOWS static std::set processIds; +#else +static std::set processIds; #endif std::recursive_mutex OS::consoleMutex; void OS::TerminateAll() { std::lock_guard guard(processIdMutex); -#ifdef TARGET_OS_WINDOWS for (auto a : processIds) + { +#ifdef TARGET_OS_WINDOWS TerminateProcess(a, 0); +#else + kill(a, 0); #endif + } } std::string OS::QuoteCommand(std::string exe, std::string command) { std::string rv; - bool sh = exe.find("sh.exe") != std::string::npos || exe.find("bash.exe") != std::string::npos; + bool sh = exe.find("sh") != std::string::npos; if (command.empty() == false && command.find_first_of(" \t\n\v\"") == command.npos) { rv = command; @@ -192,10 +208,7 @@ bool OS::TakeJob() localJobServer->TakeNewJob(); return false; } -bool OS::TryTakeJob() -{ - return localJobServer->TryTakeNewJob() != -1; -} +bool OS::TryTakeJob() { return localJobServer->TryTakeNewJob() != -1; } void OS::GiveJob() { localJobServer->ReleaseJob(); } std::string OS::GetFullPath(const std::string& fullname) { @@ -213,6 +226,14 @@ std::string OS::GetFullPath(const std::string& fullname) { // Do error handling somewhere } +#else + // https://pubs.opengroup.org/onlinepubs/000095399/functions/realpath.html + recievingbuffer.resize(PATH_MAX); + if (realpath(fullname.c_str(), recievingbuffer.data())) + { + recievingbuffer.resize(strlen(recievingbuffer.c_str())); + return recievingbuffer; + } #endif return recievingbuffer; } @@ -238,7 +259,9 @@ void OS::InitJobServer() } else { - std::cerr << "An attempt to remake a job server has been performed, this should not happen, please contact the developers if this message appears" << std::endl; + std::cerr << "An attempt to remake a job server has been performed, this should not happen, please contact the developers " + "if this message appears" + << std::endl; } } bool OS::first = false; @@ -512,7 +535,60 @@ int OS::Spawn(const std::string command, EnvironmentStrings& environment, std::s # endif return rv; #else - return -1; + std::vector parent_strs; + for (auto&& str : environment) + { + parent_strs.push_back(str.name + "=" + str.value); + } + std::vector strs; + + for (auto&& str : parent_strs) + { + strs.push_back(const_cast(str.data())); + } + strs.push_back(nullptr); + posix_spawn_file_actions_t spawn_file_actions; + posix_spawn_file_actions_init(&spawn_file_actions); + posix_spawnattr_t spawn_attr; + posix_spawnattr_init(&spawn_attr); + + pid_t default_pid = 0; + auto shell_var = VariableContainer::Instance()->Lookup("SHELL"); + // Default to a basic shell if we have an issue + std::string shell_var_value = "/bin/sh"; + if (shell_var != nullptr) + { + shell_var_value = shell_var->GetValue(); + } + else + { + OS::WriteToConsole( + "Warning: The current shell var for $(SHELL) somehow is not set according to OS::Spawn, please report this to the " + "developers!"); + } + const char* args[] = {shell_var_value.c_str(), "-c", command.c_str(), nullptr}; + + int ret = posix_spawn(&default_pid, shell_var_value.c_str(), &spawn_file_actions, &spawn_attr, args, strs.data()); + if (ret != 0) + { + posix_spawn_file_actions_destroy(&spawn_file_actions); + posix_spawnattr_destroy(&spawn_attr); + return -1; + } + int status; + int ret_wait = 0; + do + { + ret_wait = waitpid(default_pid, &status, WUNTRACED | WCONTINUED); + if (ret == -1) + { + // Some error state has happened + OS::WriteToConsole("An error has occured!"); + } + } while (!WIFEXITED(status)); + posix_spawn_file_actions_destroy(&spawn_file_actions); + posix_spawnattr_destroy(&spawn_attr); + return 0; #endif } std::string OS::SpawnWithRedirect(const std::string command) @@ -585,7 +661,68 @@ std::string OS::SpawnWithRedirect(const std::string command) CloseHandle(pipeWriteDuplicate); return rv; #else - return ""; + posix_spawn_file_actions_t spawn_file_actions; + posix_spawn_file_actions_init(&spawn_file_actions); + posix_spawnattr_t spawn_attr; + posix_spawnattr_init(&spawn_attr); + + pid_t default_pid = 0; + auto shell_var = VariableContainer::Instance()->Lookup("SHELL"); + // Default to a basic shell if we have an issue + std::string shell_var_value = "/bin/sh"; + if (shell_var != nullptr) + { + shell_var_value = shell_var->GetValue(); + } + else + { + OS::WriteToConsole( + "Warning: The current shell var for $(SHELL) somehow is not set according to OS::Spawn, please report this to the " + "developers!"); + } + + // Basing a lot of following code on this, but not directly: + // https://stackoverflow.com/a/27328610 + + int cout_pipe[2]; + pipe(cout_pipe); + + int pipefd = cout_pipe[0]; + // Close out the child-side when the process closes + posix_spawn_file_actions_addclose(&spawn_file_actions, cout_pipe[0]); + // Send the stdout pipe on the child to the cout pipe(?) + posix_spawn_file_actions_adddup2(&spawn_file_actions, cout_pipe[1], 1); + posix_spawn_file_actions_addclose(&spawn_file_actions, cout_pipe[1]); + const char* args[] = {shell_var_value.c_str(), "-c", command.c_str(), nullptr}; + int ret = posix_spawn(&default_pid, shell_var_value.c_str(), &spawn_file_actions, &spawn_attr, (char* const*)args, environ); + posix_spawn_file_actions_destroy(&spawn_file_actions); + posix_spawnattr_destroy(&spawn_attr); + + close(cout_pipe[0]); + + if (ret != 0) + { + return ""; + } + int status; + int ret_wait = 0; + std::string readable; + do + { + ret_wait = waitpid(default_pid, &status, WUNTRACED | WCONTINUED); + if (ret == -1) + { + // Some error state has happened + OS::WriteToConsole("An error has occured!"); + } + else + { + char bytes_to_read[1024]; + int bytes = read(default_pid, bytes_to_read, sizeof(bytes_to_read)); + readable += std::string(bytes_to_read, bytes); + } + } while (!WIFEXITED(status)); + return readable; #endif } Time OS::GetCurrentTime() @@ -606,7 +743,9 @@ Time OS::GetCurrentTime() Time rv(t, systemTime.wMilliseconds); return rv; #else - Time rv; + auto cur_time = std::chrono::system_clock::now(); + auto secs = std::chrono::duration_cast(cur_time.time_since_epoch()); + Time rv(secs.count(), std::chrono::duration_cast(cur_time.time_since_epoch()).count()); return rv; #endif } @@ -633,9 +772,18 @@ Time OS::GetFileTime(const std::string fileName) Time rv(t, systemTime.wMilliseconds); return rv; } +#else + struct stat file_status; + if (stat(fileName.c_str(), &file_status) == 0) + { + // POSIX-2008 uses timespecs per spec https://www.man7.org/linux/man-pages/man3/stat.3type.html + struct timespec ts = file_status.st_mtim; + // S and MS of the file, + Time rv(ts.tv_sec, ts.tv_nsec / 1'000'000); + return rv; + } #endif - Time rv; - return rv; + return Time(); } void OS::SetFileTime(const std::string fileName, Time time) { @@ -662,25 +810,25 @@ void OS::SetFileTime(const std::string fileName, Time time) ::SetFileTime(h, nullptr, nullptr, &mod); CloseHandle(h); } +#else + int fd = open(fileName.c_str(), 0); + if (fd > 0) + { + struct timespec times[2]; + + clock_gettime(CLOCK_REALTIME, ×[0]); + times[1] = times[0]; + futimens(fd, times); + close(fd); + } #endif } std::string OS::GetWorkingDir() { - char buf[260]; - getcwd(buf, 260); + char buf[PATH_MAX]; + getcwd(buf, PATH_MAX); return buf; } -void OS::CreateThread(void* func, void* data) -{ -#ifdef TARGET_OS_WINDOWS -# ifdef BCC32c - DWORD tid; - CloseHandle(::CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)func, data, 0, &tid)); -# else - CloseHandle((HANDLE)_beginthreadex(nullptr, 0, (unsigned(CALLBACK*)(void*))func, data, 0, nullptr)); -# endif -#endif -} bool OS::SetWorkingDir(const std::string name) { return !chdir(name.c_str()); } void OS::RemoveFile(const std::string name) { unlink(name.c_str()); } std::string OS::NormalizeFileName(const std::string file) @@ -707,7 +855,7 @@ std::string OS::NormalizeFileName(const std::string file) } else if (isSHEXE) { - if (name[i] == '\\' && (!i || name[i-1] != '=')) + if (name[i] == '\\' && (!i || name[i - 1] != '=')) name[i] = '/'; } else if (name[i] == '/' && i > 0 && !isspace(name[i - 1])) diff --git a/src/omake/os_specific/Linux/Linux_Jobserver.cpp b/src/omake/os_specific/Linux/Linux_Jobserver.cpp index 6df02d1f2..a1c393894 100644 --- a/src/omake/os_specific/Linux/Linux_Jobserver.cpp +++ b/src/omake/os_specific/Linux/Linux_Jobserver.cpp @@ -14,7 +14,7 @@ bool POSIXJobServer::TryTakeNewJob() { throw std::runtime_error("Job server used without initializing the underlying parameters"); } -// if (current_jobs != 0) + // if (current_jobs != 0) { int err = 0; char only_buffer; @@ -40,8 +40,8 @@ bool POSIXJobServer::TryTakeNewJob() } } } -// current_jobs++; -// return true; + // current_jobs++; + return false; } bool POSIXJobServer::TakeNewJob() { @@ -49,7 +49,7 @@ bool POSIXJobServer::TakeNewJob() { throw std::runtime_error("Job server used without initializing the underlying parameters"); } -// if (current_jobs != 0) + // if (current_jobs != 0) { int err = 0; char only_buffer; @@ -76,8 +76,8 @@ bool POSIXJobServer::TakeNewJob() } } } -// current_jobs++; -// return true; + // current_jobs++; + return false; } bool POSIXJobServer::ReleaseJob() { @@ -89,7 +89,7 @@ bool POSIXJobServer::ReleaseJob() { throw std::runtime_error("Job server has returned more jobs than it has consumed"); } - else //if (current_jobs != 1) + else // if (current_jobs != 1) { int err = 0; char write_buffer = '1'; @@ -143,12 +143,12 @@ static int populate_pipe(int writefd, int max_jobs) #endif std::this_thread::yield(); goto try_again; - break; default: throw std::system_error(err, std::system_category()); } } } + return true; } POSIXJobServer::POSIXJobServer(int max_jobs) { @@ -157,11 +157,15 @@ POSIXJobServer::POSIXJobServer(int max_jobs) { throw std::invalid_argument("The max_jobs that a JobServer has cannot be less than one at the time of construction"); } - if (pipe(readwrite) == -1) + if (pipe(readwrite) != -1) { readfd = readwrite[0]; writefd = readwrite[1]; } + else + { + throw std::system_error(errno, std::generic_category()); + } populate_pipe(writefd, max_jobs); } POSIXJobServer::POSIXJobServer(int read, int write) diff --git a/src/omake/semaphores.h b/src/omake/semaphores.h index 75957565b..7bcf7bcd0 100644 --- a/src/omake/semaphores.h +++ b/src/omake/semaphores.h @@ -46,9 +46,11 @@ class Semaphore #else // 0 in this case means this is shared internally, not externally int ret = sem_init(&handle, 0, value); - if (!ret) + // https://www.man7.org/linux/man-pages/man3/sem_init.3.html + // IT RETURNS 0 ON SUCCESS + if (ret != 0) { - throw std::runtime_error("Semaphore init failed, errno is: " + std::to_string(errno)); + throw std::system_error(errno, std::system_category()); } #endif } @@ -65,9 +67,9 @@ class Semaphore #else // 0 in this case means this is shared internally, not externally int ret = sem_init(&handle, 0, value); - if (!ret) + if (ret != 0) { - throw std::runtime_error("Semaphore init failed, errno is: " + std::to_string(errno)); + throw std::system_error(errno, std::system_category()); } #endif } @@ -85,7 +87,7 @@ class Semaphore { throw std::invalid_argument("OpenSemaphore failed, presumably bad name, Error code: " + std::to_string(errno)); } - handle =*ret; + handle = *ret; #endif } Semaphore& operator=(const Semaphore& other) @@ -109,7 +111,7 @@ class Semaphore { throw std::invalid_argument("OpenSemaphore failed, presumably bad name, Error code: " + std::to_string(errno)); } - handle =*ret; + handle = *ret; #endif } } @@ -126,16 +128,16 @@ class Semaphore if (!null) { #ifdef TARGET_OS_WINDOWS - CloseHandle(other.handle); + CloseHandle(other.handle); #else - if (named) - { - sem_close(&handle); - } - else - { - sem_destroy(&handle); - } + if (named) + { + sem_close(&handle); + } + else + { + sem_destroy(&handle); + } #endif } named = other.named; @@ -151,7 +153,7 @@ class Semaphore { throw std::invalid_argument("OpenSemaphore failed, presumably bad name, Error code: " + std::to_string(errno)); } - handle =*ret; + handle = *ret; #endif } other.named = false; @@ -159,14 +161,14 @@ class Semaphore #ifdef TARGET_OS_WINDOWS CloseHandle(other.handle); #else - if (named) - { - sem_close(&handle); - } - else - { - sem_destroy(&handle); - } + if (named) + { + sem_close(&handle); + } + else + { + sem_destroy(&handle); + } #endif } return *this; @@ -218,10 +220,9 @@ class Semaphore return false; } #else - timespec ts = { waitTime/1000, (waitTime%1000) * 1000000 }; + timespec ts = {waitTime / 1000, (waitTime % 1000) * 1000000}; return !sem_timedwait(&handle, &ts); #endif - } bool TryWait() { @@ -239,7 +240,7 @@ class Semaphore return false; } #else - return !! sem_trywait(&handle); + return !!sem_trywait(&handle); #endif } void Wait() diff --git a/src/util/ToolChain.cpp b/src/util/ToolChain.cpp index 3bbf38464..4145f7a34 100644 --- a/src/util/ToolChain.cpp +++ b/src/util/ToolChain.cpp @@ -94,7 +94,7 @@ void ToolChain::Usage(const char* text, int exitVal) left = rows - 1; } } - exit(1); + exit(0); } CmdFiles ToolChain::StandardToolStartup(CmdSwitchParser& SwitchParser, int argc, char** argv, const char* usageText, const char* helpText, std::function noBanner) diff --git a/src/util/Utils.cpp b/src/util/Utils.cpp index feab6e7f4..24b6642a0 100644 --- a/src/util/Utils.cpp +++ b/src/util/Utils.cpp @@ -1,30 +1,30 @@ /* Software License Agreement - * + * * Copyright(C) 1994-2024 David Lindauer, (LADSoft) - * + * * This file is part of the Orange C Compiler package. - * + * * The Orange C Compiler package is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. - * + * * The Orange C Compiler package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with Orange C. If not, see . - * + * * contact information: * email: TouchStone222@runbox.com - * - * + * + * */ #ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS #endif #include #include @@ -38,6 +38,7 @@ # define _access access # define _isatty isatty # include +# include #else # include extern "C" char* getcwd(char*, int); @@ -215,7 +216,7 @@ std::string Utils::SearchForFile(const std::string& path, const std::string& nam current = fpath.substr(0, npos); fpath.erase(0, npos + 1); } - if (current[current.size()-1] != CmdFiles::DIR_SEP[0]) + if (current[current.size() - 1] != CmdFiles::DIR_SEP[0]) { current += CmdFiles::DIR_SEP; } @@ -302,7 +303,7 @@ FILE* Utils::TempName(std::string& name) StrCpy(tempFile, ".\\"); tmpnam(tempFile + strlen(tempFile)); // this next because it apparently isn't standard how to do the return value of tmpnam - const char *p = strrchr(tempFile, '\\'); + const char* p = strrchr(tempFile, '\\'); strcpy(tempFile + 2, p); fil = fopen(tempFile, "w"); @@ -321,7 +322,7 @@ FILE* Utils::TempName(std::string& name) void Utils::AddExt(char* buffer, const char* ext) { char* pos = (char*)strrchr(buffer, '.'); - if (!pos || strcmp(pos,ext) != 0) + if (!pos || strcmp(pos, ext) != 0) strcat(buffer, ext); }