summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.gitmodules6
-rw-r--r--Jenkinsfile25
-rw-r--r--bootstrap.bat25
-rwxr-xr-xclrun.sh27
-rw-r--r--ctor.cc22
m---------getopt-for-windows0
m---------json0
-rw-r--r--src/configure.cc81
-rw-r--r--src/ctor.h1
-rw-r--r--src/deps.cc74
-rw-r--r--src/execute.cc248
-rw-r--r--src/rebuild.cc13
-rw-r--r--src/task_ar.cc2
-rw-r--r--src/task_cc.cc2
-rw-r--r--src/task_ld.cc24
-rw-r--r--src/task_so.cc2
-rw-r--r--src/tools.cc295
-rw-r--r--src/util.cc53
-rw-r--r--test/ctor.cc41
-rw-r--r--test/execute_test.cc12
-rw-r--r--test/source_type_test.cc8
-rwxr-xr-xtest/suite/test.sh2
-rw-r--r--test/testprog.cc38
-rw-r--r--test/tmpfile.h31
-rw-r--r--test/tools_test.cc3
26 files changed, 989 insertions, 47 deletions
diff --git a/.gitignore b/.gitignore
index 4a8a9cb..6310280 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,7 @@
drumgizmo/
build/
ctor
+ctor.exe
*.a
*.o
*.d
diff --git a/.gitmodules b/.gitmodules
index c765825..383739b 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,9 @@
[submodule "test/uunit"]
path = test/uunit
url = git://git.drumgizmo.org/uunit.git
+[submodule "getopt-for-windows"]
+ path = getopt-for-windows
+ url = https://github.com/Chunde/getopt-for-windows.git
+[submodule "json"]
+ path = json
+ url = https://github.com/nlohmann/json.git
diff --git a/Jenkinsfile b/Jenkinsfile
index a558359..cc659ab 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -5,6 +5,31 @@ pipeline {
{
parallel {
////////////////////////////////////////////////////
+ stage('Windows msvc') {
+ agent { label 'win10 && msvc' }
+ environment
+ {
+ VSDEVCMD="C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools\\Common7\\Tools\\VsDevCmd.bat"
+ }
+ steps {
+ echo 'Cleaning workspace ...'
+ bat 'git clean -d -x -f'
+ dir ('build/test') {
+ writeFile file:'dummy', text:''
+ }
+ bat '"%VSDEVCMD%" && bootstrap.bat && ctor.exe'
+ echo 'Testing (msvc) ...'
+ bat 'ctor.exe check'
+ }
+ post {
+ always {
+ xunit(thresholds: [ skipped(failureThreshold: '0'),
+ failed(failureThreshold: '0') ],
+ tools: [ CppUnit(pattern: 'build/test/*.xml') ])
+ }
+ }
+ }
+ ////////////////////////////////////////////////////
stage('MacOSX clang') {
agent { label 'macos' }
steps {
diff --git a/bootstrap.bat b/bootstrap.bat
new file mode 100644
index 0000000..3802663
--- /dev/null
+++ b/bootstrap.bat
@@ -0,0 +1,25 @@
+@echo off
+
+set CXX=cl.exe
+set CC=cl.exe
+set AR=lib.exe
+set LD=link.exe
+
+echo Bootstrapping...
+%CXX% /nologo /MT /std:c++20 /D_X86_ /EHsc /Isrc /Fo:build\ ctor.cc src\bootstrap.cc /link /out:ctor.exe
+@if %errorlevel% neq 0 exit /b %errorlevel%
+
+ctor.exe
+@if %errorlevel% neq 0 exit /b %errorlevel%
+
+%CXX% /nologo /std:c++20 /D_X86_ /EHsc /Isrc /Fo:build\ ctor.cc /c
+@if %errorlevel% neq 0 exit /b %errorlevel%
+%CXX% /nologo /std:c++20 /D_X86_ /EHsc /Isrc /Fo:build\test\ test\ctor.cc /c
+@if %errorlevel% neq 0 exit /b %errorlevel%
+%LD% /nologo build\libctor.lib build\ctor.obj build\test\ctor.obj /subsystem:console /out:ctor.exe
+@if %errorlevel% neq 0 exit /b %errorlevel%
+
+ctor.exe configure --ctor-includedir=src --ctor-libdir=build
+@if %errorlevel% neq 0 exit /b %errorlevel%
+
+@echo Done. Now run ctor.exe to (re)build.
diff --git a/clrun.sh b/clrun.sh
new file mode 100755
index 0000000..d0f3cbb
--- /dev/null
+++ b/clrun.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+#set -e
+#set -x
+export WINEDEBUG=-all
+
+rm -f ~/.wine/drive_c/number
+
+export BASE='C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.29.30133'
+export ONECORELIB="$BASE\lib\onecore\x86"
+export WINEPATH="$BASE\bin\Hostx86\x86"
+export INCLUDE="$BASE\include"
+export UCRT="C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\ucrt"
+export UCRTLIB="C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\ucrt\x86"
+export UM="C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um"
+export UMLIB="C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x86"
+export SHARED="C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared"
+
+export CL="/I\"$BASE\include\" /I\"$UCRT\" /I\"$UM\" /I\"$SHARED\" /link /LIBPATH:\"$UMLIB\" /LIBPATH:\"$ONECORELIB\" /LIBPATH:\"$UCRTLIB\""
+export LINK="/LIBPATH:\"$UMLIB\" /LIBPATH:\"$ONECORELIB\" /LIBPATH:\"$UCRTLIB\""
+export LIB="/LIBPATH:\"$UMLIB\" /LIBPATH:\"$ONECORELIB\" /LIBPATH:\"$UCRTLIB\""
+
+
+
+#wine ctor.exe
+
+$*
+
diff --git a/ctor.cc b/ctor.cc
index 67b1465..7f49255 100644
--- a/ctor.cc
+++ b/ctor.cc
@@ -31,8 +31,23 @@ ctor::build_configurations ctorConfigs(const ctor::settings& settings)
"src/tools.cc",
"src/util.cc",
"src/unittest.cc",
+ {ctor::toolchain::msvc, "getopt-for-windows/getopt.c"},
},
.flags = {
+ .cflags = {
+ "-O3",
+// "-g",
+// "-Wall",
+// "-Wconversion",
+// "-Wextra",
+ //"-Werror",
+ "-Isrc",
+ {ctor::toolchain::msvc, ctor::c_opt::custom, "/Igetopt-for-windows"},
+ {ctor::toolchain::msvc, ctor::c_opt::custom, "/D_X86_"},
+ {ctor::toolchain::msvc, ctor::c_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::c_opt::custom, "/external:W0"},
+ {ctor::toolchain::msvc, ctor::c_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
+ },
.cxxflags = {
"-std=c++20",
"-O3",
@@ -44,6 +59,13 @@ ctor::build_configurations ctorConfigs(const ctor::settings& settings)
"-Wconversion",
// "-Wnrvo",
"-Isrc",
+ "-Ijson/include",
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/Igetopt-for-windows"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_X86_"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/external:W0"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/Dstrdup=_strdup"},
},
},
}
diff --git a/getopt-for-windows b/getopt-for-windows
new file mode 160000
+Subproject 76fe2df86f84771775fd2f1a641a09adbce28df
diff --git a/json b/json
new file mode 160000
+Subproject 6be4e8560023098fdb6d2047e6e6e5bc5dd5287
diff --git a/src/configure.cc b/src/configure.cc
index a43152f..b52824e 100644
--- a/src/configure.cc
+++ b/src/configure.cc
@@ -8,6 +8,8 @@
#include <fstream>
#include <optional>
#include <span>
+#include <vector>
+#include <deque>
#include <getoptpp/getoptpp.hpp>
@@ -25,7 +27,11 @@ const std::filesystem::path configHeaderFile("config.h");
std::map<std::string, std::string> external_includedir;
std::map<std::string, std::string> external_libdir;
+#if !defined(_WIN32)
const ctor::configuration& __attribute__((weak)) ctor::get_configuration()
+#else
+const ctor::configuration& default_get_configuration()
+#endif
{
static ctor::configuration cfg;
static bool initialised{false};
@@ -44,6 +50,14 @@ const ctor::configuration& __attribute__((weak)) ctor::get_configuration()
}
return cfg;
}
+#if defined(_WIN32)
+// Hack to make ctor::get_configuration "weak" linked
+// See:
+// https://stackoverflow.com/questions/2290587/gcc-style-weak-linking-in-visual-studio
+// and
+// https://stackoverflow.com/questions/11849853/how-to-list-functions-present-in-object-file
+#pragma comment(linker, "/alternatename:?get_configuration@ctor@@YAABUconfiguration@1@XZ=?default_get_configuration@@YAABUconfiguration@ctor@@XZ")
+#endif
namespace ctor {
std::optional<std::string> includedir;
@@ -100,11 +114,47 @@ std::string ctor::configuration::get(const std::string& key,
return ctor::conf_values[key];
}
- if(has(key))
+ if(tools.find(key) != tools.end())
{
return tools.at(key);
}
+ if(key == ctor::cfg::build_cxx)
+ {
+ auto e = std::getenv("CXX");
+ if(e)
+ {
+ return e;
+ }
+ }
+
+ if(key == ctor::cfg::build_cc)
+ {
+ auto e = std::getenv("CC");
+ if(e)
+ {
+ return e;
+ }
+ }
+
+ if(key == ctor::cfg::build_ld)
+ {
+ auto e = std::getenv("LD");
+ if(e)
+ {
+ return e;
+ }
+ }
+
+ if(key == ctor::cfg::build_ar)
+ {
+ auto e = std::getenv("AR");
+ if(e)
+ {
+ return e;
+ }
+ }
+
return default_value;
}
@@ -162,6 +212,9 @@ std::ostream& operator<<(std::ostream& stream, const ctor::toolchain& toolchain)
case ctor::toolchain::gcc:
stream << "ctor::toolchain::gcc";
break;
+ case ctor::toolchain::msvc:
+ stream << "ctor::toolchain::msvc";
+ break;
case ctor::toolchain::clang:
stream << "ctor::toolchain::clang";
break;
@@ -676,6 +729,7 @@ int regenerateCache(ctor::settings& settings,
{
ctor::conf_values[ctor::cfg::builddir] = builddir;
}
+
ctor::conf_values[ctor::cfg::host_cxx] = host_cxx;
ctor::conf_values[ctor::cfg::build_cxx] = build_cxx;
@@ -906,6 +960,31 @@ int configure(const ctor::settings& global_settings, int argc, char* argv[])
env["PATH"] = path_env;
}
+ // Env vars for msvc
+ auto cl_env = getenv("CL");
+ if(cl_env)
+ {
+ env["CL"] = cl_env;
+ }
+
+ auto lib_env = getenv("LIB");
+ if(lib_env)
+ {
+ env["LIB"] = lib_env;
+ }
+
+ auto link_env = getenv("LINK");
+ if(link_env)
+ {
+ env["LINK"] = link_env;
+ }
+
+ auto include_env = getenv("INCLUDE");
+ if(include_env)
+ {
+ env["INCLUDE"] = include_env;
+ }
+
auto ret = regenerateCache(settings, args_span[0], args, env);
if(ret != 0)
{
diff --git a/src/ctor.h b/src/ctor.h
index 9c6fcf6..4deee98 100644
--- a/src/ctor.h
+++ b/src/ctor.h
@@ -59,6 +59,7 @@ enum class toolchain
none,
gcc,
clang,
+ msvc,
};
struct source
diff --git a/src/deps.cc b/src/deps.cc
index 9400b35..599be8c 100644
--- a/src/deps.cc
+++ b/src/deps.cc
@@ -5,6 +5,8 @@
#include "util.h"
+#include <nlohmann/json.hpp>
+
#include <fstream>
namespace {
@@ -94,6 +96,74 @@ std::vector<std::string> readDepsMake(const std::string& dep_file)
return output;
}
+
+// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1689r5.html
+// https://devblogs.microsoft.com/cppblog/introducing-source-dependency-reporting-with-msvc-in-visual-studio-2019-version-16-7/
+/* Format examples:
+{
+ "Version": "1.1",
+ "Data": {
+ "Source": "z:\\home\\deva\\docs\\c\\ctor\\src\\libctor.cc",
+ "ProvidedModule": "",
+ "Includes": [
+ "c:\\program files (x86)\\microsoft visual studio\\2019\\buildtools\\vc\\tools\\msvc\\14.29.30133\\include\\vector",
+ "c:\\program files (x86)\\microsoft visual studio\\2019\\buildtools\\vc\\tools\\msvc\\14.29.30133\\include\\yvals_core.h",
+ "c:\\program files (x86)\\microsoft visual studio\\2019\\buildtools\\vc\\tools\\msvc\\14.29.30133\\include\\vcruntime.h",
+.
+.
+.
+ "z:\\home\\deva\\docs\\c\\ctor\\src\\unittest.h"
+ ],
+ "ImportedModules": [],
+ "ImportedHeaderUnits": []
+ }
+}
+*/
+/*
+{
+ "Version": "1.2",
+ "Data": {
+ "Source": "c:\\jenkins\\workspace\\ctor-linux64\\src\\build.cc",
+ "ProvidedModule": "",
+ "Includes": [
+ "c:\\jenkins\\workspace\\ctor-linux64\\src\\build.h",
+ "c:\\program files (x86)\\microsoft visual studio\\2022\\buildtools\\vc\\tools\\msvc\\14.42.34433\\include\\string",
+ "c:\\program files (x86)\\microsoft visual studio\\2022\\buildtools\\vc\\tools\\msvc\\14.42.34433\\include\\yvals_core.h",
+.
+.
+.
+ "c:\\program files (x86)\\microsoft visual studio\\2022\\buildtools\\vc\\tools\\msvc\\14.42.34433\\include\\iostream"
+ ],
+ "ImportedModules": [],
+ "ImportedHeaderUnits": []
+ }
+}
+*/
+
+std::vector<std::string> readDepsJson(const std::string& dep_file)
+{
+ std::ifstream stream(dep_file);
+ auto json = nlohmann::json::parse(stream);
+ for(const auto& [key, value] : json.items())
+ {
+ if(key == "Data" && value.is_object())
+ {
+ for(const auto& [inner_key, inner_value] : value.items())
+ {
+ if(inner_key == "Includes" && inner_value.is_array())
+ {
+ std::vector<std::string> deps;
+ for(const auto& dep : inner_value)
+ {
+ deps.emplace_back(dep);
+ }
+ return deps;
+ }
+ }
+ }
+ }
+ return {};
+}
}
std::vector<std::string> readDeps(const std::string& dep_file,
@@ -110,6 +180,10 @@ std::vector<std::string> readDeps(const std::string& dep_file,
case ctor::toolchain::none:
return {};
+ // json based:
+ case ctor::toolchain::msvc:
+ return readDepsJson(dep_file);
+
// makefile .d file based:
case ctor::toolchain::gcc:
case ctor::toolchain::clang:
diff --git a/src/execute.cc b/src/execute.cc
index c050732..4ed274f 100644
--- a/src/execute.cc
+++ b/src/execute.cc
@@ -6,12 +6,24 @@
#include "ctor.h"
#include "pointerlist.h"
-#include <unistd.h>
-#include <cstring>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <spawn.h>
+#if !defined(_WIN32)
+ #include <unistd.h>
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ #include <spawn.h>
+ extern char **environ;
+#else
+ #define WINDOWS_LEAN_AND_MEAN
+ #include <windows.h>
+ #undef max
+ #include <thread>
+#endif
+
#include <iostream>
+#include <cstring>
+#include <vector>
+#include <deque>
+#include <filesystem>
/*
https://blog.famzah.net/2009/11/20/a-much-faster-popen-and-system-implementation-for-linux/
@@ -23,7 +35,7 @@ https://stackoverflow.com/questions/4259629/what-is-the-difference-between-fork-
namespace
{
-
+#if !defined(_WIN32)
int parent_waitpid(pid_t pid)
{
int status{};
@@ -61,9 +73,80 @@ int parent_waitpid(pid_t pid)
// Should never happen...
return 1;
}
-} // namespace ::
+#endif //_WIN32
+
+#if defined(_WIN32)
+std::string getLastErrorAsString()
+{
+ DWORD errorMessageID = ::GetLastError();
+ if(errorMessageID == 0)
+ {
+ return {};
+ }
+
+ LPSTR message_buffer{};
+ auto size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ nullptr,
+ errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&message_buffer, 0, nullptr);
+
+ std::string message(message_buffer, size);
+ LocalFree(message_buffer);
+ return message;
+}
+
+int moveSelf(const ctor::settings& settings)
+{
+ int cnt{0};
+ char source[MAX_PATH];
+ HMODULE module = GetModuleHandle(0);
+ GetModuleFileNameA(module, source, MAX_PATH);
+
+ while(true)
+ {
+ if(cnt > 10) // If we need to try more than 10 times something is wrong
+ {
+ return 1;
+ }
+
+ std::filesystem::path tmp_file = settings.builddir;
+ tmp_file /= "tmp";
+ std::string target = tmp_file.string() + "-" + std::to_string(cnt);
+ if(MoveFileA(source, target.data()))
+ {
+ break; // success
+ }
+
+ auto err = GetLastError();
+ if(err == ERROR_ALREADY_EXISTS)
+ {
+ if(DeleteFileA(target.data()))
+ {
+ continue; // Try again
+ }
+
+ err = GetLastError();
+ if(err != ERROR_ACCESS_DENIED)
+ {
+ std::cerr << "Could not delete file\n";
+ return err;
+ }
-extern char **environ; // see 'man environ'
+ cnt++;
+ continue; // Increment and try again
+ }
+ else
+ {
+ std::cerr << "Could not move file\n";
+ return err;
+ }
+ }
+ return 0;
+}
+#endif // _WIN32
+} // namespace ::
int execute(const ctor::settings& settings,
const std::string& command,
@@ -98,11 +181,13 @@ int execute(const ctor::settings& settings,
std::cout << cmd << std::endl;
}
+#if !defined(_WIN32)
+
#if 1
auto pid = vfork();
if(pid == 0)
{
- EnvMap envmap((const char**)environ);
+ EnvMap envmap(environ);
for(const auto& [key, value] : env)
{
envmap.insert(key + "=" + value);
@@ -120,15 +205,16 @@ int execute(const ctor::settings& settings,
}
return parent_waitpid(pid);
#elif 0
- pid_t pid;
- std::vector<std::string> venv;
+ pid_t pid{};
+ EnvMap envmap(environ);
for(const auto& [key, value] : env)
{
- venv.push_back(key + "=" + value);
+ envmap.insert(key + "=" + value);
}
- Env penv(venv);
+
+ auto [_, envv] = envmap.get();
if(posix_spawn(&pid, command.data(), nullptr, nullptr,
- (char**)argv.data(), penv.data()))
+ (char**)argv.data(), const_cast<char* const *>(envv)))
{
return 1;
}
@@ -138,5 +224,139 @@ int execute(const ctor::settings& settings,
return system(cmd.data());
#endif
+#else // _WIN32
+ if(terminate)
+ {
+ auto ret = moveSelf(settings);
+ if(ret != 0)
+ {
+ return ret;
+ }
+ }
+
+ auto env_strings = GetEnvironmentStrings();
+ EnvMap envmap(env_strings);
+ FreeEnvironmentStrings(env_strings);
+ for(const auto& [key, value] : env)
+ {
+ envmap.insert(key + "=" + value);
+ }
+
+ // TODO: Use SetDllDirectory(...) to set DLL search directory?
+
+ SECURITY_ATTRIBUTES security_attr;
+ // Set the bInheritHandle flag so pipe handles are inherited.
+ security_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ security_attr.bInheritHandle = TRUE;
+ security_attr.lpSecurityDescriptor = nullptr;
+
+ HANDLE stream_in_read{};
+ HANDLE stream_in_write{};
+ HANDLE stream_out_read{};
+ HANDLE stream_out_write{};
+
+ if(!CreatePipe(&stream_out_read, &stream_out_write, &security_attr, 0))
+ {
+ std::cout << "Error CreatePipe (out): " << getLastErrorAsString() << "\n";
+ }
+
+ if(!SetHandleInformation(stream_out_read, HANDLE_FLAG_INHERIT, 0))
+ {
+ std::cout << "Error - SetHandleInformation (out): " << getLastErrorAsString() << "\n";
+ }
+
+ // Create a pipe for the child process's STDIN.
+ if(!CreatePipe(&stream_in_read, &stream_in_write, &security_attr, 0))
+ {
+ std::cout << "Error CreatePipe (in): " << getLastErrorAsString() << "\n";
+ }
+
+ // Ensure the write handle to the pipe for STDIN is not inherited.
+ if(!SetHandleInformation(stream_in_write, HANDLE_FLAG_INHERIT, 0))
+ {
+ std::cout << "Error - SetHandleInformation (in): " << getLastErrorAsString() << "\n";
+ }
+
+ STARTUPINFO si{};
+ si.hStdInput = GetStdHandle(((DWORD)-10));//STD_INPUT_HANDLE
+ si.hStdOutput = stream_out_write;
+ si.hStdError = stream_out_write;
+ si.dwFlags |= STARTF_USESTDHANDLES;
+
+ PROCESS_INFORMATION pi{};
+
+ si.cb = sizeof(si);
+
+ if(!CreateProcess(nullptr, // lpApplicationName
+ (char*)cmd.data(), // lpCommandLine
+ nullptr, // lpProcessAttributes
+ nullptr, // lpThreadAttributes
+ TRUE, // bInheritHandles
+ INHERIT_PARENT_AFFINITY |
+ 0x00000200 | // CREATE_NEW_PROCESS_GROUP
+ 0, // dwCreationFlags
+ envmap.stringify().data(), // lpEnvironment
+ nullptr, // lpCurrentDirectory
+ &si, // lpStartupInfo
+ &pi)) // lpProcessInformation
+ {
+ std::cout << "Could not execute " << command << ": " <<
+ getLastErrorAsString() << "\n";
+ return 1;
+ }
+
+ int ignore_lines{};
+ std::filesystem::path cmd_path{command};
+ if(cmd_path.filename() == "cl.exe")
+ {
+ // Ignore first line, avoiding the annoying msvc compiler of printing the filename
+ // of the file that is being compiled
+ ignore_lines = 1;
+ }
+
+ std::atomic<bool> running{true};
+ auto parent_waitpid = std::thread([&](){
+ WaitForSingleObject(pi.hProcess, INFINITE);
+ CloseHandle(stream_out_write);
+ CloseHandle(stream_in_read);
+ running.store(false);
+ });
+
+ CHAR buf[1024];
+ while(running.load())
+ {
+ if(WaitForSingleObject(stream_out_read, 0) != WAIT_OBJECT_0)
+ {
+ Sleep(1);
+ continue;
+ }
+ DWORD read_bytes{};
+ auto res = ReadFile(stream_out_read, buf, sizeof(buf), &read_bytes, nullptr);
+ if(res != TRUE || read_bytes == 0)
+ {
+ break;
+ }
+ std::string str;
+ str.append(buf, read_bytes);
+ if(ignore_lines == 0)
+ {
+ std::cout << str << std::flush;
+ }
+ if(str.find('\n') != std::string::npos)
+ {
+ ignore_lines = std::max(0, ignore_lines - 1);
+ }
+ }
+
+ DWORD exit_code{};
+ GetExitCodeProcess(pi.hProcess, &exit_code);
+ parent_waitpid.join();
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+
+ return exit_code;
+#endif // _WIN32
+
return 1;
}
diff --git a/src/rebuild.cc b/src/rebuild.cc
index a2b7ddd..9a3fca0 100644
--- a/src/rebuild.cc
+++ b/src/rebuild.cc
@@ -38,7 +38,10 @@ int reg(ctor::build_configurations (*cb)(const ctor::settings&),
{
auto pwd = std::filesystem::current_path();
auto rel = std::filesystem::relative(loc, pwd);
- configFiles[numConfigFiles].file = strdup(rel.string().data()); // NOTE: This intentionally leaks memory
+ auto str = rel.string();
+ auto file = new char[str.size() + 1];
+ strncpy(file, str.data(), str.size() + 1);
+ configFiles[numConfigFiles].file = file; // NOTE: This intentionally leaks memory
}
else
{
@@ -169,6 +172,8 @@ bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[
config.flags.cxxflags.emplace_back(ctor::cxx_opt::optimization, "3");
config.flags.cxxflags.emplace_back(ctor::cxx_opt::cpp_std, "c++20");
+ config.flags.cxxflags.push_back({ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"});
+
const auto& c = ctor::get_configuration();
if(c.has(ctor::cfg::ctor_includedir))
{
@@ -180,9 +185,13 @@ bool recompileCheck(const ctor::settings& global_settings, int argc, char* argv[
config.flags.ldflags.emplace_back(ctor::ld_opt::library_path,
c.get(ctor::cfg::ctor_libdir));
}
- config.flags.ldflags.emplace_back(ctor::ld_opt::link, "ctor");
+ config.flags.ldflags.emplace_back(ctor::toolchain::msvc, ctor::ld_opt::link, "libctor.lib");
+ config.flags.ldflags.emplace_back(ctor::toolchain::gcc, ctor::ld_opt::link, "ctor");
+ config.flags.ldflags.emplace_back(ctor::toolchain::clang, ctor::ld_opt::link, "ctor");
config.flags.ldflags.emplace_back(ctor::ld_opt::threads);
+ config.flags.ldflags.push_back({ctor::toolchain::msvc, ctor::ld_opt::custom, "/subsystem:console"});
+
ctor::settings settings{global_settings};
settings.verbose = -1; // Make check completely silent.
diff --git a/src/task_ar.cc b/src/task_ar.cc
index 3b45cc2..0365d51 100644
--- a/src/task_ar.cc
+++ b/src/task_ar.cc
@@ -93,6 +93,8 @@ int TaskAR::runInner()
append(args, ar_option(toolchain, ctor::ar_opt::add_index));
append(args, ar_option(toolchain, ctor::ar_opt::create));
append(args, ar_option(toolchain, ctor::ar_opt::output, targetFile().string()));
+ append(args, to_strings(toolchain, {ctor::toolchain::msvc, ctor::ar_opt::custom, "/nologo"}));
+
for(const auto& task : getDependsTasks())
{
args.push_back(task->targetFile().string());
diff --git a/src/task_cc.cc b/src/task_cc.cc
index 9628455..b300cd6 100644
--- a/src/task_cc.cc
+++ b/src/task_cc.cc
@@ -305,12 +305,14 @@ std::vector<std::string> TaskCC::flags() const
{
append(flags, to_strings(toolchain, flag));
}
+ append(flags, to_strings(toolchain, {ctor::toolchain::msvc, ctor::c_opt::custom, "/nologo"}));
return flags;
case ctor::language::cpp:
for(const auto& flag : config.flags.cxxflags)
{
append(flags, to_strings(toolchain, flag));
}
+ append(flags, to_strings(toolchain, {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/nologo"}));
return flags;
default:
std::cerr << "Unknown CC target type\n";
diff --git a/src/task_ld.cc b/src/task_ld.cc
index 03745be..af71bbb 100644
--- a/src/task_ld.cc
+++ b/src/task_ld.cc
@@ -115,6 +115,7 @@ int TaskLD::runInner()
}
append(args, ld_option(toolchain, ctor::ld_opt::output, targetFile().string()));
+ append(args, to_strings(toolchain, {ctor::toolchain::msvc, ctor::ld_opt::custom, "/nologo"}));
{ // Write flags to file.
std::ofstream flagsStream(flagsFile);
@@ -129,11 +130,28 @@ int TaskLD::runInner()
auto tool = compiler();
const auto& cfg = ctor::get_configuration();
- auto ldflags = cfg.getenv("LDFLAGS");
- if(!ldflags.empty())
+ if(toolchain == ctor::toolchain::gcc ||
+ toolchain == ctor::toolchain::clang)
{
- append(args, ld_option(toolchain, ctor::ld_opt::custom, ldflags));
+ auto ldflags = cfg.getenv("LDFLAGS");
+ if(!ldflags.empty())
+ {
+ append(args, ld_option(toolchain, ctor::ld_opt::custom, ldflags));
+ }
}
+ else // msvc
+ {
+ switch(outputSystem())
+ {
+ case ctor::output_system::host:
+ tool = cfg.get(ctor::cfg::host_ld, "/usr/bin/ld");
+ break;
+ case ctor::output_system::build:
+ tool = cfg.get(ctor::cfg::build_ld, "/usr/bin/ld");
+ break;
+ }
+ }
+
auto res = execute(settings, tool, args, cfg.env, is_self);
if(res != 0)
{
diff --git a/src/task_so.cc b/src/task_so.cc
index 92aeefe..db07c53 100644
--- a/src/task_so.cc
+++ b/src/task_so.cc
@@ -93,6 +93,8 @@ int TaskSO::runInner()
append(args, ld_option(toolchain, ctor::ld_opt::output, targetFile().string()));
+ append(args, to_strings(toolchain, {ctor::toolchain::msvc, ctor::ld_opt::custom, "/nologo"}));
+
for(const auto& task : getDependsTasks())
{
args.push_back(task->targetFile().string());
diff --git a/src/tools.cc b/src/tools.cc
index dfabdff..1a539be 100644
--- a/src/tools.cc
+++ b/src/tools.cc
@@ -6,6 +6,7 @@
#include <filesystem>
#include <iostream>
#include <sstream>
+#include <algorithm>
#include <array>
#include <cassert>
@@ -13,6 +14,11 @@
#include "util.h"
+#if defined(_WIN32)
+#define popen _popen
+#define pclose _pclose
+#endif
+
std::ostream& operator<<(std::ostream& stream, const ctor::c_opt& opt)
{
// Adding to this enum should also imply adding to the unit-tests below
@@ -129,6 +135,10 @@ ctor::toolchain getToolChain(const std::string& compiler)
{
return ctor::toolchain::gcc;
}
+ else if(to_lower(cc_cmd).find("cl") != std::string::npos)
+ {
+ return ctor::toolchain::msvc;
+ }
std::cerr << "Unsupported output system.\n";
return ctor::toolchain::gcc;
@@ -154,12 +164,256 @@ ctor::toolchain getToolChain(ctor::output_system system)
return getToolChain(cfg.get(ctor::cfg::build_cxx, "g++"));
}
}
+namespace msvc {
+std::string get_arch([[maybe_unused]] ctor::output_system system)
+{
+ return "windows";
+}
+
+ctor::arch get_arch([[maybe_unused]] const std::string& str)
+{
+ return ctor::arch::windows;
+}
+
+ctor::c_flag c_option(const std::string& flag)
+{
+ if(flag.starts_with("/I"))
+ {
+ std::string path = flag.substr(2);
+ path.erase(0, path.find_first_not_of(' '));
+ return { ctor::c_opt::include_path, path };
+ }
+
+ return { ctor::c_opt::custom, flag };
+}
+
+ctor::cxx_flag cxx_option(const std::string& flag)
+{
+ if(flag.starts_with("/I"))
+ {
+ std::string path = flag.substr(2);
+ path.erase(0, path.find_first_not_of(' '));
+ return { ctor::cxx_opt::include_path, path };
+ }
+
+ return { ctor::cxx_opt::custom, flag };
+}
+
+ctor::ld_flag ld_option(const std::string& flag)
+{
+ if(flag.starts_with("/L"))
+ {
+ std::string path = flag.substr(2);
+ path.erase(0, path.find_first_not_of(' '));
+ return { ctor::ld_opt::library_path, path };
+ }
+
+ return { ctor::ld_opt::custom, flag };
+}
+
+ctor::ar_flag ar_option(const std::string& flag)
+{
+ return { ctor::ar_opt::custom, flag };
+}
+
+std::vector<std::string> cxx_option(ctor::cxx_opt opt, const std::string& arg,
+ const std::string& arg2)
+{
+ switch(opt)
+ {
+ case ctor::cxx_opt::output:
+ return {"/Fo\"" + arg + "\""};
+ case ctor::cxx_opt::debug:
+ return {"/DEBUG"};
+ case ctor::cxx_opt::warn_all:
+ return {"/W4"};
+ case ctor::cxx_opt::warn_conversion:
+ return {"/W4"}; // TODO: This is incorrect
+ case ctor::cxx_opt::warn_shadow:
+ return {"/W4"}; // TODO: This is incorrect
+ case ctor::cxx_opt::warn_extra:
+ return {"/W4"}; // TODO: This is incorrect
+ case ctor::cxx_opt::warnings_as_errors:
+ return {"/WX"};
+ case ctor::cxx_opt::generate_dep_tree:
+ return {"/sourceDependencies", arg};
+ case ctor::cxx_opt::no_link:
+ return {"/c"};
+ case ctor::cxx_opt::include_path:
+ return {"/I" + arg};
+ case ctor::cxx_opt::cpp_std:
+ return {"/std:" + arg};
+ case ctor::cxx_opt::optimization:
+ {
+ int o{0};
+ try
+ {
+ o = std::stoi(arg);
+ o = std::clamp(o, 0, 2);
+ }
+ catch(...)
+ {
+ // bad number?
+ }
+ return {"/O" + std::to_string(o)};
+ }
+ case ctor::cxx_opt::position_independent_code:
+ return {}; // TODO?
+ case ctor::cxx_opt::position_independent_executable:
+ return {}; // TODO?
+ case ctor::cxx_opt::define:
+ if(!arg2.empty())
+ {
+ return {"/D" + arg + "=" + esc(arg2)};
+ }
+ else
+ {
+ return {"/D" + arg};
+ }
+ case ctor::cxx_opt::custom:
+ return {arg};
+ }
+
+ std::cerr << "Unsupported compiler option.\n";
+ return {};
+}
+
+std::vector<std::string> c_option(ctor::c_opt opt, const std::string& arg,
+ const std::string& arg2)
+{
+ switch(opt)
+ {
+ case ctor::c_opt::output:
+ return {"/Fo\"" + arg + "\""};
+ case ctor::c_opt::debug:
+ return {"/DEBUG"};
+ case ctor::c_opt::warn_all:
+ return {"/W4"};
+ case ctor::c_opt::warn_conversion:
+ return {"/W4"}; // TODO: This is incorrect
+ case ctor::c_opt::warn_shadow:
+ return {"/W4"}; // TODO: This is incorrect
+ case ctor::c_opt::warn_extra:
+ return {"/W4"}; // TODO: This is incorrect
+ case ctor::c_opt::warnings_as_errors:
+ return {"/WX"};
+ case ctor::c_opt::generate_dep_tree:
+ return {"/sourceDependencies", arg};
+ case ctor::c_opt::no_link:
+ return {"/c"};
+ case ctor::c_opt::include_path:
+ return {"/I" + arg};
+ case ctor::c_opt::c_std:
+ return {"/std:" + arg};
+ case ctor::c_opt::optimization:
+ {
+ int o{0};
+ try
+ {
+ o = std::stoi(arg);
+ o = std::clamp(o, 0, 2);
+ }
+ catch(...)
+ {
+ // bad number?
+ }
+ return {"/O" + std::to_string(o)};
+ }
+ case ctor::c_opt::position_independent_code:
+ return {}; // TODO?
+ case ctor::c_opt::position_independent_executable:
+ return {}; // TODO?
+ case ctor::c_opt::define:
+ if(!arg2.empty())
+ {
+ return {"/D" + arg + "=" + esc(arg2)};
+ }
+ else
+ {
+ return {"/D" + arg};
+ }
+ case ctor::c_opt::custom:
+ return {arg};
+ }
+
+ std::cerr << "Unsupported compiler option.\n";
+ return {};
+}
+
+std::vector<std::string> ld_option(ctor::ld_opt opt, const std::string& arg,
+ [[maybe_unused]]const std::string& arg2)
+{
+ switch(opt)
+ {
+ case ctor::ld_opt::output:
+ return {"/out:" + arg + ""};
+ case ctor::ld_opt::warn_all:
+ return {"/Wall"};
+ case ctor::ld_opt::warnings_as_errors:
+ return {"/WX"};
+ case ctor::ld_opt::library_path:
+ return {"/LIBPATH:\""+arg+"\""};
+ case ctor::ld_opt::link:
+ return {arg}; // TODO?
+ case ctor::ld_opt::cpp_std:
+ return {"/std:" + arg};
+ case ctor::ld_opt::build_shared:
+ return {}; // TODO?
+ case ctor::ld_opt::threads:
+ return {}; // TODO?
+ case ctor::ld_opt::position_independent_code:
+ return {}; // TODO?
+ case ctor::ld_opt::position_independent_executable:
+ return {}; // TODO?
+ case ctor::ld_opt::custom:
+ return {arg};
+ }
+
+ std::cerr << "Unsupported compiler option.\n";
+ return {};
+}
+
+std::vector<std::string> ar_option(ctor::ar_opt opt, const std::string& arg,
+ [[maybe_unused]]const std::string& arg2)
+{
+ switch(opt)
+ {
+ case ctor::ar_opt::replace:
+ return {};
+ case ctor::ar_opt::add_index:
+ return {};
+ case ctor::ar_opt::create:
+ return {};
+ case ctor::ar_opt::output:
+ return {"/out:" + arg};
+ case ctor::ar_opt::custom:
+ return {arg};
+ }
+
+ std::cerr << "Unsupported compiler option.\n";
+ return {};
+}
+
+std::vector<std::string> asm_option(ctor::asm_opt opt, const std::string& arg,
+ [[maybe_unused]]const std::string& arg2)
+{
+ switch(opt)
+ {
+ case ctor::asm_opt::custom:
+ return {arg};
+ }
+
+ std::cerr << "Unsupported compiler option.\n";
+ return {};
+}
+} // msvc::
+
namespace gcc {
-std::string get_arch(ctor::output_system system)
+std::string get_arch([[maybe_unused]] ctor::output_system system)
{
+ std::string arch;
std::string cmd;
-
const auto& c = ctor::get_configuration();
switch(system)
{
@@ -180,7 +434,6 @@ std::string get_arch(ctor::output_system system)
return {};//ctor::arch::unknown;
}
- std::string arch;
while(!feof(pipe))
{
constexpr auto buffer_size{1024};
@@ -571,6 +824,8 @@ std::string get_arch(ctor::output_system system)
case ctor::toolchain::clang:
case ctor::toolchain::gcc:
return gcc::get_arch(system);
+ case ctor::toolchain::msvc:
+ return msvc::get_arch(system);
case ctor::toolchain::any:
case ctor::toolchain::none:
break;
@@ -586,6 +841,8 @@ ctor::arch get_arch(ctor::output_system system, const std::string& str)
case ctor::toolchain::clang:
case ctor::toolchain::gcc:
return gcc::get_arch(str);
+ case ctor::toolchain::msvc:
+ return msvc::get_arch(str);
case ctor::toolchain::any:
case ctor::toolchain::none:
break;
@@ -603,6 +860,8 @@ std::vector<std::string> c_option(ctor::toolchain toolchain,
case ctor::toolchain::gcc:
case ctor::toolchain::clang:
return gcc::c_option(opt, arg, arg2);
+ case ctor::toolchain::msvc:
+ return msvc::c_option(opt, arg, arg2);
case ctor::toolchain::any:
{
std::ostringstream ss;
@@ -636,6 +895,8 @@ std::vector<std::string> cxx_option(ctor::toolchain toolchain,
case ctor::toolchain::gcc:
case ctor::toolchain::clang:
return gcc::cxx_option(opt, arg, arg2);
+ case ctor::toolchain::msvc:
+ return msvc::cxx_option(opt, arg, arg2);
case ctor::toolchain::any:
{
std::ostringstream ss;
@@ -669,6 +930,8 @@ std::vector<std::string> ld_option(ctor::toolchain toolchain,
case ctor::toolchain::gcc:
case ctor::toolchain::clang:
return gcc::ld_option(opt, arg, arg2);
+ case ctor::toolchain::msvc:
+ return msvc::ld_option(opt, arg, arg2);
case ctor::toolchain::any:
{
std::ostringstream ss;
@@ -702,6 +965,8 @@ std::vector<std::string> ar_option(ctor::toolchain toolchain,
case ctor::toolchain::gcc:
case ctor::toolchain::clang:
return gcc::ar_option(opt, arg, arg2);
+ case ctor::toolchain::msvc:
+ return msvc::ar_option(opt, arg, arg2);
case ctor::toolchain::any:
{
std::ostringstream ss;
@@ -735,6 +1000,8 @@ std::vector<std::string> asm_option(ctor::toolchain toolchain,
case ctor::toolchain::gcc:
case ctor::toolchain::clang:
return gcc::asm_option(opt, arg, arg2);
+ case ctor::toolchain::msvc:
+ return msvc::asm_option(opt, arg, arg2);
case ctor::toolchain::any:
{
std::ostringstream ss;
@@ -766,6 +1033,8 @@ ctor::c_flag c_option(const std::string& flag, ctor::toolchain toolchain)
case ctor::toolchain::gcc:
case ctor::toolchain::clang:
return gcc::c_option(flag);
+ case ctor::toolchain::msvc:
+ return msvc::c_option(flag);
case ctor::toolchain::any:
case ctor::toolchain::none:
break;
@@ -781,6 +1050,8 @@ ctor::cxx_flag cxx_option(const std::string& flag, ctor::toolchain toolchain)
case ctor::toolchain::gcc:
case ctor::toolchain::clang:
return gcc::cxx_option(flag);
+ case ctor::toolchain::msvc:
+ return msvc::cxx_option(flag);
case ctor::toolchain::any:
case ctor::toolchain::none:
break;
@@ -796,6 +1067,8 @@ ctor::ld_flag ld_option(const std::string& flag, ctor::toolchain toolchain)
case ctor::toolchain::gcc:
case ctor::toolchain::clang:
return gcc::ld_option(flag);
+ case ctor::toolchain::msvc:
+ return msvc::ld_option(flag);
case ctor::toolchain::any:
case ctor::toolchain::none:
break;
@@ -811,6 +1084,8 @@ ctor::ar_flag ar_option(const std::string& flag, ctor::toolchain toolchain)
case ctor::toolchain::gcc:
case ctor::toolchain::clang:
return gcc::ar_option(flag);
+ case ctor::toolchain::msvc:
+ return msvc::ar_option(flag);
case ctor::toolchain::any:
case ctor::toolchain::none:
break;
@@ -825,6 +1100,7 @@ ctor::asm_flag asm_option(const std::string& flag, ctor::toolchain toolchain)
{
case ctor::toolchain::gcc:
case ctor::toolchain::clang:
+ case ctor::toolchain::msvc:
case ctor::toolchain::any:
case ctor::toolchain::none:
break;
@@ -908,10 +1184,11 @@ ctor::toolchain guess_toolchain(const std::string& opt)
return ctor::toolchain::gcc;
}
- //if(opt[0] == '/')
- //{
- // return ctor::toolchain::msvc;
- //}
+ if(opt[0] == '/')
+ {
+ return ctor::toolchain::msvc;
+ }
+
return ctor::toolchain::any;
}
}
@@ -982,8 +1259,8 @@ ctor::target_type target_type_from_extension(ctor::toolchain toolchain,
}
}
- if(toolchain == ctor::toolchain::any// ||
- //toolchain == ctor::toolchain::msvc ||
+ if(toolchain == ctor::toolchain::any ||
+ toolchain == ctor::toolchain::msvc// ||
//toolchain == ctor::toolchain::mingw ||
)
{
diff --git a/src/util.cc b/src/util.cc
index 6fc650a..20dea71 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -8,10 +8,17 @@
#include <algorithm>
#include <sstream>
+namespace {
+char to_lower_c(char ch)
+{
+ return static_cast<char>(::tolower(ch));
+}
+}
+
std::string to_lower(const std::string& str)
{
std::string out{str};
- std::transform(out.begin(), out.end(), out.begin(), ::tolower);
+ std::transform(out.begin(), out.end(), out.begin(), to_lower_c);
return out;
}
@@ -20,13 +27,18 @@ std::string readFile(const std::string& fileName)
std::ifstream ifs(fileName.c_str(),
std::ios::in | std::ios::binary | std::ios::ate);
- std::ifstream::pos_type fileSize = ifs.tellg();
+ auto tell = ifs.tellg();
+ if(tell < 0)
+ {
+ return {};
+ }
+ auto fileSize = static_cast<std::size_t>(tell);
ifs.seekg(0, std::ios::beg);
- std::vector<char> bytes(static_cast<std::size_t>(fileSize));
- ifs.read(bytes.data(), fileSize);
+ std::vector<char> bytes(fileSize);
+ ifs.read(bytes.data(), static_cast<long>(bytes.size()));
- return {bytes.data(), static_cast<std::size_t>(fileSize)};
+ return { bytes.data(), bytes.size() };
}
ctor::language languageFromExtension(const std::filesystem::path& file)
@@ -71,7 +83,7 @@ namespace
{
bool isClean(char c)
{
- return c != '.' && c != '/';
+ return c != '.' && c != '/' && c != '\\';
}
}
@@ -170,15 +182,36 @@ std::string locate(const std::string& prog,
}
}
+ if(std::filesystem::exists(program + ".exe"))
+ {
+ if(check_executable(program + ".exe"))
+ {
+ return program + ".exe";
+ }
+ }
+
for(const auto& path_str : paths)
{
std::filesystem::path path(path_str);
- auto prog_path = path / program;
- if(std::filesystem::exists(prog_path))
{
- if(check_executable(prog_path))
+ auto prog_path = path / program;
+ if(std::filesystem::exists(prog_path))
+ {
+ if(check_executable(prog_path))
+ {
+ return prog_path.string();
+ }
+ }
+ }
+
+ {
+ auto prog_path = path / (program + ".exe");
+ if(std::filesystem::exists(prog_path))
{
- return prog_path.string();
+ if(check_executable(prog_path))
+ {
+ return prog_path.string();
+ }
}
}
}
diff --git a/test/ctor.cc b/test/ctor.cc
index b7bcc6d..fa53802 100644
--- a/test/ctor.cc
+++ b/test/ctor.cc
@@ -23,6 +23,8 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"argsplit\"",
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
},
},
},
@@ -40,6 +42,8 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"pointerlist\"",
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
},
},
},
@@ -58,7 +62,10 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
.cxxflags = {
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
+ "-I../json/include",
"-DOUTPUT=\"deps\"",
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
},
},
},
@@ -72,6 +79,8 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
.flags = {
.cxxflags = {
"-std=c++20", "-O3", "-Wall", "-Werror",
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
},
},
},
@@ -92,6 +101,8 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"execute\"",
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
},
.ldflags = { "-pthread" },
},
@@ -110,6 +121,8 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"tasks\"",
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
},
.ldflags = { "-pthread" },
},
@@ -128,6 +141,8 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"cycle\"",
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
},
.ldflags = { "-pthread" },
},
@@ -146,6 +161,8 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"source_type\"",
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
},
.ldflags = { "-pthread" },
},
@@ -166,6 +183,8 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src", "-Iuunit",
"-DOUTPUT=\"tools\"",
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
},
},
},
@@ -190,11 +209,33 @@ ctor::build_configurations ctorTestConfigs(const ctor::settings& settings)
"../src/tools.cc",
"../src/util.cc",
"../src/externals_manual.cc",
+ {ctor::toolchain::msvc, "../getopt-for-windows/getopt.c"},
},
.flags = {
+ .cflags = {
+ "-O3",
+// "-g",
+// "-Wall",
+// "-Wconversion",
+// "-Wextra",
+ //"-Werror",
+ "-I../src",
+ {ctor::toolchain::msvc, ctor::c_opt::custom, "/I../getopt-for-windows"},
+ {ctor::toolchain::msvc, ctor::c_opt::custom, "/D_X86_"},
+ {ctor::toolchain::msvc, ctor::c_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::c_opt::custom, "/external:W0"},
+ {ctor::toolchain::msvc, ctor::c_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
+ },
.cxxflags = {
"-std=c++20", "-O3", "-Wall", "-Werror",
"-I../src",
+ "-I../json/include",
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/I../getopt-for-windows"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_X86_"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/EHsc"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/external:W0"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/D_CRT_SECURE_NO_WARNINGS"},
+ {ctor::toolchain::msvc, ctor::cxx_opt::custom, "/Dstrdup=_strdup"},
},
.ldflags = { "-pthread" },
},
diff --git a/test/execute_test.cc b/test/execute_test.cc
index 722b6ea..6a376f8 100644
--- a/test/execute_test.cc
+++ b/test/execute_test.cc
@@ -36,11 +36,23 @@ public:
value = execute(s, "no-such-binary", {}, {}, false);
uASSERT_EQUAL(1, value);
value = execute(s, cmd, {"segfault"}, {}, false);
+#if !defined(_WIN32)
uASSERT_EQUAL(11, value);
+#else
+ uASSERT_EQUAL(3, value);
+#endif
value = execute(s, cmd, {"throw"}, {}, false);
+#if !defined(_WIN32)
uASSERT_EQUAL(6, value);
+#else
+ uASSERT_EQUAL(-1073740791, value);
+#endif
value = execute(s, cmd, {"abort"}, {}, false);
+#if !defined(_WIN32)
uASSERT_EQUAL(6, value);
+#else
+ uASSERT_EQUAL(-1073740791, value);
+#endif
}
void env()
diff --git a/test/source_type_test.cc b/test/source_type_test.cc
index 288f1e5..657260e 100644
--- a/test/source_type_test.cc
+++ b/test/source_type_test.cc
@@ -26,6 +26,14 @@ std::ostream& operator<<(std::ostream& stream, const ctor::language& lang)
return stream;
}
+const ctor::configuration& ctor::get_configuration()
+{
+ static ctor::configuration cfg{};
+ cfg.build_toolchain = ctor::toolchain::gcc;
+ cfg.build_arch = ctor::arch::unix;
+ return cfg;
+}
+
class TestableTaskCC
: public TaskCC
{
diff --git a/test/suite/test.sh b/test/suite/test.sh
index 97d2551..d57580f 100755
--- a/test/suite/test.sh
+++ b/test/suite/test.sh
@@ -1,4 +1,6 @@
#!/bin/bash
+#set -x
+
: ${CXX:=g++}
: ${CTORDIR:=../../build}
: ${BUILDDIR:=build}
diff --git a/test/testprog.cc b/test/testprog.cc
index 93edc3f..18c2c74 100644
--- a/test/testprog.cc
+++ b/test/testprog.cc
@@ -5,6 +5,14 @@
extern char **environ;
+#if defined(_WIN32)
+#define WINDOWS_LEAN_AND_MEAN
+#include <windows.h>
+#undef max
+#else
+extern char **environ; // see 'man environ'
+#endif
+
int main(int argc, const char* argv[])
{
if(argc < 2)
@@ -20,11 +28,41 @@ int main(int argc, const char* argv[])
{
return 0;
}
+
std::ofstream ostrm(argv[2], std::ios::binary);
+ if(ostrm.bad())
+ {
+ std::cout << "Error: Could not write to " << argv[2] << "\n";
+ }
+#if defined(_WIN32)
+ auto env_strings = GetEnvironmentStrings();
+ const char* ptr = env_strings;
+ std::string env;
+ while(true)
+ {
+ if(*ptr == '\0')
+ {
+ if(env.empty())
+ {
+ // no more
+ break;
+ }
+ ostrm << env << "\n";
+ env.clear();
+ ++ptr;
+ continue;
+ }
+
+ env += *ptr;
+ ++ptr;
+ }
+ FreeEnvironmentStrings(env_strings);
+#else
for(auto current = environ; *current; ++current)
{
ostrm << (*current) << "\n";
}
+#endif
}
if(cmd == "retval")
diff --git a/test/tmpfile.h b/test/tmpfile.h
index 5d114d0..a5d4043 100644
--- a/test/tmpfile.h
+++ b/test/tmpfile.h
@@ -4,7 +4,7 @@
#pragma once
#include <cstdlib>
-#include <unistd.h>
+#include <cstring>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
@@ -12,6 +12,9 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <io.h>
+#else
+#include <unistd.h>
#endif
struct tmp_file
@@ -19,23 +22,35 @@ struct tmp_file
tmp_file(const std::string& data = {})
{
int fd;
+ auto tmp_dir = std::filesystem::temp_directory_path();
+ auto tmp_file_template = tmp_dir / "ctor_tmp_file-XXXXXX";
+ filename = tmp_file_template.string();
+ auto buf = new char[filename.size() + 2];
+ memcpy(buf, filename.data(), filename.size() + 1);
#ifdef _WIN32
- char templ[] = "ctor_tmp_file-XXXXXX"; // buffer for filename
- _mktemp_s(templ, sizeof(templ));
- fd = open(templ, O_CREAT | O_RDWR);
+ _mktemp_s(buf, filename.size() + 2);
+ filename = buf;
+ fd = _open(filename.data(), O_CREAT | O_RDWR, _S_IWRITE);
+ auto sz = _write(fd, data.data(), data.size());
+ (void)sz;
+ _close(fd);
#else
- char templ[] = "/tmp/ctor_tmp_file-XXXXXX"; // buffer for filename
- fd = mkstemp(templ);
-#endif
- filename = templ;
+ fd = mkstemp(buf);
+ filename = buf;
auto sz = write(fd, data.data(), data.size());
(void)sz;
close(fd);
+#endif
+ delete[] buf;
}
~tmp_file()
{
+#ifdef _WIN32
+ _unlink(filename.data());
+#else
unlink(filename.data());
+#endif
}
const std::string& get() const
diff --git a/test/tools_test.cc b/test/tools_test.cc
index 5ae04c3..15270b3 100644
--- a/test/tools_test.cc
+++ b/test/tools_test.cc
@@ -22,6 +22,9 @@ std::ostream& operator<<(std::ostream& stream, const ctor::toolchain& toolchain)
case ctor::toolchain::clang:
stream << "ctor::toolchain::clang";
break;
+ case ctor::toolchain::msvc:
+ stream << "ctor::toolchain::msvc";
+ break;
}
return stream;
}