Issue (Part 3)
Add Windows platform support
Highlights -
* Swapping Posix functions for std functions
* Fixing a few include file related issues to get code
compiling on Windows.
MODIFY
src/API/slapi_scripts.i
src/API/slapi_scripts.i
-/* File: slapi.i */
+/* File: slapi_scripts.i */
%module slapi
%include "typemaps.i"
%include "std_string.i"

MODIFY
src/CommandLine/CommandLineParser.cpp
src/CommandLine/CommandLineParser.cpp
#include <limits.h>
#include <sstream>
-#include <stdlib.h>
+#include <cstdlib>
#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>
@@ -395,6 +395,9 @@ void CommandLineParser::processArgs_(std::vector<std::string>& args,
// Try to find the full absolute path of the program currently running.
static std::string GetProgramNameAbsolutePath(const char *progname) {
+#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
+ const char PATH_DELIMITER = ';';
+#else
char buf[PATH_MAX];
// If the executable is invoked with a path, we can extract it from there,
// otherwise, we use some operating system trick to find that path:
@@ -405,16 +408,20 @@ static std::string GetProgramNameAbsolutePath(const char *progname) {
const char *const program_name = realpath(testpath, buf);
if (program_name) return program_name;
}
+ const char PATH_DELIMITER = ':';
+#endif
// Still not found, let's go through the $PATH and see what comes up first.
- const char *const path = getenv("PATH");
+ const char *const path = std::getenv("PATH");
if (path) {
std::stringstream search_path(path);
std::string path_element;
- while (std::getline(search_path, path_element, ':')) {
+ std::string program_path;
+ while (std::getline(search_path, path_element, PATH_DELIMITER)) {
const std::string testpath = path_element + "/" + progname;
- const char *const program_name = realpath(testpath.c_str(), buf);
- if (program_name) return program_name;
+ if (FileUtils::getFullPath(testpath, &program_path)) {
+ return program_path;
+ }
}
}

MODIFY
src/DesignCompile/CompileDesign.cpp
src/DesignCompile/CompileDesign.cpp
#include "tbb/task_scheduler_init.h"
#endif
+#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
+ #include <process.h> // Has to be included before <thread>
+#endif
+
#include <vector>
#include <thread>

MODIFY
src/ErrorReporting/ErrorContainer.cpp
src/ErrorReporting/ErrorContainer.cpp
@@ -44,7 +44,9 @@ ErrorContainer::ErrorContainer(SymbolTable* symbolTable)
/* Do nothing here */
}
+#if !(defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
#include <unistd.h>
+#endif
#include <stdio.h>
void ErrorContainer::init() {

MODIFY
src/ErrorReporting/Report.cpp
src/ErrorReporting/Report.cpp
#include "ErrorReporting/Report.h"
#include <iostream>
#include <fstream>
-#include <unistd.h>
#include <iomanip>
#include <regex>
#include <mutex>
+#include <chrono>
+#include <thread>
+
+#if !(defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
+ #include <unistd.h>
+#endif
+
using namespace SURELOG;
Report::Report() {}
@@ -99,7 +105,7 @@ std::pair<bool, bool> Report::makeDiffCompUnitReport(CommandLineParser* clp,
Result readUnitResult;
while ((!readAll) || (!readUnit)) {
- usleep(1000);
+ std::this_thread::sleep_for(std::chrono::microseconds(1000));
if (!readAll) {
readAll = parseReportFile(alllog, readAllResult);
}

MODIFY
src/SourceCompile/Compiler.cpp
src/SourceCompile/Compiler.cpp
@@ -44,6 +44,11 @@ using namespace antlr4;
#include "API/PythonAPI.h"
#include "SourceCompile/CheckCompile.h"
+
+#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
+ #include <process.h> // Has to be included before <thread>
+#endif
+
#include <mutex>
#include <thread>
#include <vector>

MODIFY
src/Utils/FileUtils.cpp
src/Utils/FileUtils.cpp
#include "Utils/FileUtils.h"
#include "Utils/StringUtils.h"
#include <sys/stat.h>
-#include <unistd.h>
#include <string.h>
#include <limits.h> /* PATH_MAX */
#include <errno.h>
#include <iostream>
#include <algorithm>
#include <string>
-#include <dirent.h>
#include <stdio.h>
#include <regex>
#include <fstream>
#include <sstream>
+#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
+ #include <direct.h>
+ #define PATH_MAX _MAX_PATH
+ // Supress the warning for the time being until we upgrade to C++17
+ #define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
+#else
+ #include <dirent.h>
+ #include <unistd.h>
+#endif
+
+#if (__cplusplus >= 201703L) && __has_include(<filesystem>)
+ #include <filesystem>
+ namespace fs = std::filesystem;
+#else
+ #include <experimental/filesystem>
+ namespace fs = std::experimental::filesystem;
+#endif
+
using namespace SURELOG;
FileUtils::FileUtils() {}
@@ -60,15 +76,11 @@ unsigned long FileUtils::fileSize(const std::string name) {
}
bool FileUtils::fileIsDirectory(const std::string name) {
- struct stat statbuf;
- if (stat(name.c_str(), &statbuf) != 0) return 0;
- return S_ISDIR(statbuf.st_mode);
+ return fs::is_directory(name);
}
bool FileUtils::fileIsRegular(const std::string name) {
- struct stat statbuf;
- if (stat(name.c_str(), &statbuf) != 0) return 0;
- return S_ISREG(statbuf.st_mode);
+ return fs::is_regular_file(name);
}
SymbolId FileUtils::locateFile(SymbolId file, SymbolTable* symbols,
@@ -92,64 +104,32 @@ SymbolId FileUtils::locateFile(SymbolId file, SymbolTable* symbols,
}
int FileUtils::mkDir(const char* path) {
- /* Adapted from http://stackoverflow.com/a/2336245/119527 */
- const size_t len = strlen(path);
- char _path[PATH_MAX];
- char* p;
-
- errno = 0;
-
- /* Copy string so its mutable */
- if (len > sizeof(_path) - 1) {
- errno = ENAMETOOLONG;
- return -1;
- }
- strcpy(_path, path);
-
- /* Iterate the string */
- for (p = _path + 1; *p; p++) {
- if (*p == '/') {
- /* Temporarily truncate */
- *p = '\0';
- if (mkdir(_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
- if (errno != EEXIST) return -1;
- }
-
- *p = '/';
- }
- }
-
- if (mkdir(_path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
- if (errno != EEXIST) return -1;
- }
-
- return 0;
+ // CAUTION: There is a known bug in VC compiler where a trailing
+ // slash in the path will cause a false return from a call to
+ // fs::create_directories.
+ const std::string dirpath(path);
+ fs::create_directories(dirpath);
+ return fs::is_directory(dirpath) ? 0 : -1;
}
std::string FileUtils::getPathName(const std::string path) {
- char sep = '/';
-
-#ifdef _WIN32
- sep = '\\';
-#endif
-
- size_t i = path.rfind(sep, path.length());
- if (i != std::string::npos) {
- return (path.substr(0, i)) + "/";
+ return (fs::path(path).parent_path() += fs::path::preferred_separator).string();
}
- return ("");
+std::string FileUtils::getFullPath(const std::string path) {
+ std::error_code ec;
+ fs::path fullPath = fs::canonical(path, ec);
+ return ec ? path : fullPath.string();
}
-std::string FileUtils::getFullPath(const std::string path) {
- char* full_path = realpath(path.c_str(), NULL);
- std::string ret;
- if (full_path) {
- ret = full_path;
- free(full_path);
- } else
- ret = path;
- return ret;
+bool FileUtils::getFullPath(const std::string path, std::string* const result) {
+ std::error_code ec;
+ fs::path fullPath = fs::canonical(path, ec);
+ if (!ec && fileIsRegular(fullPath.string())) {
+ if (result != nullptr) *result = fullPath.string();
+ return true;
+ }
+ return false;
}
static bool has_suffix(const std::string& s, const std::string& suffix) {
@@ -166,26 +146,15 @@ std::vector<SymbolId> FileUtils::collectFiles(SymbolId dirPath, SymbolId ext,
std::vector<SymbolId> FileUtils::collectFiles(const std::string dirPath,
const std::string ext,
SymbolTable* symbols) {
- std::string path = dirPath;
- if (path.size()) {
- if (path[path.size() - 1] != '/') {
- path += "/";
- }
- }
std::vector<SymbolId> result;
- DIR* dir = opendir(path.c_str());
- if (!dir) {
- return result;
+ if (fileIsDirectory(dirPath)) {
+ for (fs::directory_entry entry : fs::directory_iterator(dirPath)) {
+ const std::string filepath = entry.path().string();
+ if (has_suffix(filepath, ext)) {
+ result.push_back(symbols->registerSymbol(filepath));
}
-
- dirent* entry;
- while ((entry = readdir(dir)) != NULL) {
- if (has_suffix(entry->d_name, ext)) {
- result.push_back(symbols->registerSymbol(path + entry->d_name));
}
}
-
- closedir(dir);
return result;
}
@@ -193,8 +162,7 @@ std::vector<SymbolId> FileUtils::collectFilesRegexp(const std::string dirPath,
const std::string regexp,
SymbolTable* symbols) {
std::vector<SymbolId> result;
- DIR* dir = opendir(dirPath.c_str());
- if (!dir) {
+ if (!fileIsDirectory(dirPath)) {
return result;
}
@@ -217,15 +185,13 @@ std::vector<SymbolId> FileUtils::collectFilesRegexp(const std::string dirPath,
std::regex base_regex(newregexp);
std::smatch base_match;
- dirent* entry;
- while ((entry = readdir(dir)) != NULL) {
- std::string value = entry->d_name;
+ for (fs::directory_entry entry : fs::directory_iterator(dirPath)) {
+ std::string value = entry.path().string();
if (std::regex_match(value, base_match, base_regex)) {
- result.push_back(symbols->registerSymbol(entry->d_name));
+ result.push_back(symbols->registerSymbol(value));
}
}
- closedir(dir);
return result;
}
@@ -322,3 +288,4 @@ std::string FileUtils::fileName(std::string str) {
str.erase(str.begin(), it1.base());
return str;
}
+

MODIFY
src/Utils/FileUtils.h
src/Utils/FileUtils.h
#ifndef FILEUTILS_H
#define FILEUTILS_H
+
+#include <string>
#include <vector>
namespace SURELOG {
+typedef uint64_t SymbolId;
+class SymbolTable;
+
class FileUtils {
public:
static bool fileExists(const std::string name);
@@ -36,6 +41,7 @@ class FileUtils {
const std::vector<SymbolId>& paths);
static int mkDir(const char* path);
static std::string getFullPath(const std::string path);
+ static bool getFullPath(const std::string path, std::string *const result);
static std::string getPathName(const std::string path);
static std::string fileName(std::string str);
static unsigned long fileSize(const std::string name);

MODIFY
src/main.cpp
src/main.cpp
@@ -205,6 +205,14 @@ int main(int argc, const char ** argv) {
switch (mode) {
case DIFF:
{
+ #if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
+ // REVISIT: Windows doesn't have the concept of forks!
+ // Implement it sequentially for now and optimize it if this
+ // proves to be a bottleneck (preferably, implemented as a
+ // cross platform solution).
+ executeCompilation(argc, argv, true, false);
+ codedReturn = executeCompilation(argc, argv, true, true);
+ #else
pid_t pid = fork();
if (pid == 0) {
// child process
@@ -217,7 +225,7 @@ int main(int argc, const char ** argv) {
printf("fork() failed!\n");
return 1;
}
- break;
+ #endif
}
case NORMAL:
codedReturn = executeCompilation(argc, argv, false, false);

Issue #239 (Part 3)
Add Windows platform support

Highlights -
* Swapping Posix functions for std functions
* Fixing a few include file related issues to get code
  compiling on Windows.