diff --git a/CMakeLists.txt b/CMakeLists.txt index aa006b6..962cfe1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,50 +1,47 @@ -cmake_minimum_required (VERSION 3.2) -project(compilescript - VERSION 0.4.0 - LANGUAGES CXX -) +# Support version 3.6 and above, but use policy settings up to 3.14. +# 3.6 is needed because of IMPORTED_TARGET in pkg_check_modules(). +cmake_minimum_required(VERSION 3.6...3.14) +# Ranges are supported from 3.12, set policy to current for < 3.12. +if(${CMAKE_VERSION} VERSION_LESS 3.12) + cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) +endif() -include(GNUInstallDirs) -find_package(PkgConfig REQUIRED) -pkg_check_modules(LIBXDG_BASEDIR REQUIRED libxdg-basedir) -pkg_check_modules(LIBCONFIG REQUIRED libconfig++) +project(compilescript + VERSION 0.4.0 + LANGUAGES CXX) +# DESCRIPTION was introduced in version 3.9. +if(NOT (${CMAKE_VERSION} VERSION_LESS 3.9)) + set(PROJECT_DESCRIPTION + "Execute source files from compiled languages as scripts.") +endif() + +option(WITH_MAN "Compile and install manpage." YES) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -set(CMAKE_CXX_FLAGS_DEBUG - "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Wpedantic -ftrapv -fsanitize=undefined -g -Og -fno-omit-frame-pointer") - -include_directories(${PROJECT_BINARY_DIR}) -include_directories(${LIBXDG_BASEDIR_INCLUDE_DIRS}) -include_directories(${LIBCONFIG_INCLUDE_DIRS}) - -link_directories(${LIBXDG_BASEDIR_LIBRARY_DIRS}) -link_directories(${LIBCONFIG_LIBRARY_DIRS}) - -# Write version in header -configure_file( - "${PROJECT_SOURCE_DIR}/src/version.hpp.in" - "${PROJECT_BINARY_DIR}/version.hpp" -) - -file(GLOB sources src/*.cpp) -add_executable(${CMAKE_PROJECT_NAME} "${sources}") -target_link_libraries(${CMAKE_PROJECT_NAME} - "${LIBXDG_BASEDIR_LDFLAGS} ${LIBCONFIG_LDFLAGS}" - "-lstdc++fs") -install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR}) - -set(WITH_MAN "YES" CACHE STRING "WITH_MAN defaults to \"YES\"") -if (WITH_MAN) - add_custom_command(OUTPUT "${PROJECT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.1" - WORKING_DIRECTORY "${PROJECT_BINARY_DIR}" - DEPENDS "${CMAKE_SOURCE_DIR}/${CMAKE_PROJECT_NAME}.1.adoc" - COMMAND ${CMAKE_SOURCE_DIR}/build_manpage.sh - ARGS ${PROJECT_VERSION}) - add_custom_target(run ALL - DEPENDS "${PROJECT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.1") - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.1 - DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) +set(DEBUG_CXXFLAGS + "-Wall" + "-Wextra" + "-Wpedantic" + "-ftrapv" + "-fsanitize=undefined" + "-g" + "-Og" + "-fno-omit-frame-pointer") +set(DEBUG_LDFLAGS + "-fsanitize=undefined") +add_compile_options("$<$:${DEBUG_CXXFLAGS}>") +# add_link_options was introduced in version 3.13. +if(${CMAKE_VERSION} VERSION_LESS 3.13) + set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${DEBUG_LDFLAGS}") +else() + add_link_options("$<$:${DEBUG_LDFLAGS}>") +endif() + +add_subdirectory(src) + +if (WITH_MAN) + add_subdirectory(man) endif() diff --git a/man/CMakeLists.txt b/man/CMakeLists.txt new file mode 100644 index 0000000..9fb0b7b --- /dev/null +++ b/man/CMakeLists.txt @@ -0,0 +1,14 @@ +include(GNUInstallDirs) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.1" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + DEPENDS "${PROJECT_NAME}.1.adoc" + COMMAND "${PROJECT_SOURCE_DIR}/man/build_manpage.sh" + ARGS "${PROJECT_VERSION}") + +add_custom_target(man ALL + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.1") + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.1 + DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) diff --git a/build_manpage.sh b/man/build_manpage.sh similarity index 62% rename from build_manpage.sh rename to man/build_manpage.sh index fcf5497..7a308ec 100755 --- a/build_manpage.sh +++ b/man/build_manpage.sh @@ -3,9 +3,10 @@ name="compilescript" if [ -n "${1}" ]; then - dir="$(dirname ${0})" + dir=$(dirname "${0}") + version=${1} cp -vf "${dir}/${name}.1.adoc" . - sed -Ei "s/(Revision: +)[0-9]+\.[0-9]\.[0-9]/\1${1}/" "${name}.1.adoc" + sed -Ei "s/(Revision: +)[0-9]+\.[0-9]\.[0-9]/\1${version}/" "${name}.1.adoc" a2x --doctype manpage --format manpage --no-xmllint "${name}.1.adoc" else echo "usage: ${0} VERSION" >&2 diff --git a/compilescript.1.adoc b/man/compilescript.1.adoc similarity index 100% rename from compilescript.1.adoc rename to man/compilescript.1.adoc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..5ffbda4 --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,22 @@ +include(GNUInstallDirs) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(libxdg-basedir REQUIRED IMPORTED_TARGET libxdg-basedir) +pkg_check_modules(libconfig++ REQUIRED IMPORTED_TARGET libconfig++) + +# Write version in header +configure_file("version.hpp.in" "${CMAKE_CURRENT_BINARY_DIR}/version.hpp") + +set(sources "main.cpp" "../xdgcfg/src/xdgcfg.cpp") + +add_executable(${CMAKE_PROJECT_NAME} "${sources}") + +target_include_directories(${PROJECT_NAME} + PRIVATE + "${PROJECT_SOURCE_DIR}/xdgcfg/include" + "${CMAKE_CURRENT_BINARY_DIR}") + +target_link_libraries(${CMAKE_PROJECT_NAME} + PRIVATE PkgConfig::libxdg-basedir PkgConfig::libconfig++ stdc++fs) + +install(TARGETS ${CMAKE_PROJECT_NAME} DESTINATION "${CMAKE_INSTALL_BINDIR}") diff --git a/src/main.cpp b/src/main.cpp index 508a603..5d51a6f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,40 +14,54 @@ * along with this program. If not, see . */ -#if __cplusplus >= 201703L - #include -#else - #include -#endif -#include -#include -#include -#include -#include -#include -#include +#include "version.hpp" +#include "xdgcfg.hpp" #include #include -#include "xdgcfg.hpp" -#include "version.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#if __cplusplus >= 201703L - namespace fs = std::filesystem; -#else - namespace fs = std::experimental::filesystem; -#endif +namespace fs = std::experimental::filesystem; using std::cout; using std::cerr; using std::endl; using std::chrono::system_clock; using std::chrono::hours; using std::chrono::duration_cast; +using std::string; +using std::vector; -string compiler = "g++ -x c++"; -fs::path cache_dir; -int clean_after_hours = 30 * 24; +class Compilescript +{ +private: + string _compiler; + fs::path _cache_dir; + int _clean_after_hours; -bool read_settings() +public: + Compilescript(); + + void read_settings(); + void cleanup(); + bool compile(const string &filename, char *argv[]); + void print_version(); +}; + +Compilescript::Compilescript() + : _compiler("g++ -x c++") + , _clean_after_hours(30 * 24) +{} + + +void Compilescript::read_settings() { bool need_save = false; xdgcfg config("compilescript.cfg"); @@ -56,106 +70,79 @@ bool read_settings() if (cfg.exists("compiler")) { - compiler = cfg["compiler"].c_str(); + _compiler = cfg["compiler"].c_str(); } else { - cfg.add("compiler", libconfig::Setting::TypeString) = compiler; + cfg.add("compiler", libconfig::Setting::TypeString) = _compiler; need_save = true; } if (cfg.exists("clean_after_hours")) { - cfg.lookupValue("clean_after_hours", clean_after_hours); + cfg.lookupValue("clean_after_hours", _clean_after_hours); } else { cfg.add("clean_after_hours", - libconfig::Setting::TypeInt) = clean_after_hours; + libconfig::Setting::TypeInt) = _clean_after_hours; need_save = true; } if (cfg.exists("cache_dir")) { - cache_dir = cfg["cache_dir"].c_str(); + _cache_dir = cfg["cache_dir"].c_str(); } else { xdgHandle xdg; xdgInitHandle(&xdg); - cache_dir = xdgCacheHome(&xdg); - cache_dir /= "compilescript"; + _cache_dir = xdgCacheHome(&xdg); + _cache_dir /= "compilescript"; xdgWipeHandle(&xdg); } - if (!fs::is_directory(cache_dir)) + if (!fs::is_directory(_cache_dir)) { - fs::create_directories(cache_dir); + fs::create_directories(_cache_dir); } if (need_save) { config.write(); } - - return true; } -void cleanup() +void Compilescript::cleanup() { - for (const fs::directory_entry &entry - : fs::recursive_directory_iterator(cache_dir)) + for (const auto &entry : fs::recursive_directory_iterator(_cache_dir)) { - if (fs::is_regular_file(entry)) + if (!fs::is_regular_file(entry)) { - auto diff = system_clock::now() - fs::last_write_time(entry); - if (duration_cast(diff).count() > clean_after_hours) - { - fs::path current_path = entry.path(); - std::error_code e; + continue; + } - while (fs::remove(current_path, e)) + const auto diff = system_clock::now() - fs::last_write_time(entry); + if (duration_cast(diff).count() > _clean_after_hours) + { + fs::path current_path = entry.path(); + std::error_code e; + + while (fs::remove(current_path, e)) + { + current_path = current_path.parent_path(); + if (current_path == _cache_dir) { - current_path = current_path.parent_path(); - if (current_path == cache_dir) - { - break; - } + break; } } } } } -int main(int argc, char *argv[]) +bool Compilescript::compile(const string &filename, char *argv[]) { - if (!read_settings()) - { - return 1; - } - - if (argc <= 1) - { - cerr << "usage: " << argv[0] << - " [file|--cleanup|--version] [arguments]\n"; - return 1; - } - if (string(argv[1]) == "--cleanup") - { - cleanup(); - return 0; - } - if (string(argv[1]) == "--version") - { - cout << "compilescript " << global::version << endl << - "Copyright (C) 2018, 2019 tastytea \n" - "License GPLv3: GNU GPL version 3 .\n" - "This program comes with ABSOLUTELY NO WARRANTY. This is free software,\n" - "and you are welcome to redistribute it under certain conditions.\n"; - return 0; - } - - const fs::path original = fs::canonical(argv[1]); - const fs::path source = cache_dir / original; + const fs::path original = fs::canonical(filename); + const fs::path source = _cache_dir / original; const fs::path binary = (source.string() + ".bin"); string compiler_arguments; fs::create_directories(binary.parent_path()); @@ -178,7 +165,11 @@ int main(int argc, char *argv[]) } std::getline(in, buf); - if (buf.substr(0, 16) == "//compilescript:") + if (buf.substr(0, 17) == "// compilescript:") + { + compiler_arguments = buf.substr(17); + } + else if (buf.substr(0, 16) == "//compilescript:") { compiler_arguments = buf.substr(16); } @@ -204,26 +195,73 @@ int main(int argc, char *argv[]) else { cerr << "ERROR: Could not open file: " << source << endl; - return 1; + return false; } } else { cerr << "ERROR: Could not open file: " << original << endl; - return 1; + return false; } - int ret = std::system((compiler + " " + source.string() + " " + - compiler_arguments + - " -o " + binary.string()).c_str()); + const string command = _compiler + " " + source.string() + " " + + compiler_arguments + " -o " + binary.string(); + int ret = std::system(command.c_str()); // NOLINT Doesn't apply here. if (ret != 0) { cerr << "ERROR: Compilation failed.\n"; - return 1; + return false; } } - execv(binary.c_str(), &argv[1]); + execvp(binary.c_str(), &argv[1]); // NOLINT We know that argv[1] exists. + + return true; +} + +void Compilescript::print_version() +{ + cout << "compilescript " << global::version << '\n' << + "Copyright (C) 2018, 2019 tastytea \n" + "License GPLv3: GNU GPL version 3 " + ".\n" + "This program comes with ABSOLUTELY NO WARRANTY. This is free software," + "\nand you are welcome to redistribute it under certain conditions.\n"; +} + +int main(int argc, char *argv[]) +{ + const vector args(argv, argv + argc); + + Compilescript App; + App.read_settings(); + + if (args.size() <= 1) + { + cerr << "usage: " << args[0] + << " [file|--cleanup|--version] [arguments]\n"; + return 1; + } + if (args[1] == "--cleanup") + { + App.cleanup(); + return 0; + } + if (args[1] == "--version") + { + App.print_version(); + return 0; + } + + try + { + App.compile(args[1], argv); + } + catch (const std::exception &e) + { + cerr << "Error: " << e.what() << endl; + return 1; + } return 0; } diff --git a/src/version.hpp.in b/src/version.hpp.in index cec7915..c1b66ee 100644 --- a/src/version.hpp.in +++ b/src/version.hpp.in @@ -3,7 +3,7 @@ namespace global { - static constexpr char version[] = "@PROJECT_VERSION@"; +static constexpr char version[] = "@PROJECT_VERSION@"; } #endif // VERSION_HPP diff --git a/src/xdgcfg.cpp b/src/xdgcfg.cpp deleted file mode 120000 index 0f27a45..0000000 --- a/src/xdgcfg.cpp +++ /dev/null @@ -1 +0,0 @@ -../xdgcfg/src/xdgcfg.cpp \ No newline at end of file diff --git a/src/xdgcfg.hpp b/src/xdgcfg.hpp deleted file mode 120000 index f1851a8..0000000 --- a/src/xdgcfg.hpp +++ /dev/null @@ -1 +0,0 @@ -../xdgcfg/src/xdgcfg.hpp \ No newline at end of file diff --git a/xdgcfg b/xdgcfg index e22f82f..9337964 160000 --- a/xdgcfg +++ b/xdgcfg @@ -1 +1 @@ -Subproject commit e22f82fc6f1c40cda3d3ce5e671299f26f622528 +Subproject commit 9337964266ae55415beaa7f517cc4240a259289a