diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 70e540d..4af3985 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,6 +18,19 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/../.git" AND NOT EXISTS "${CMAKE_SOURCE_DIR}/../s message (FATAL_ERROR "Submodules are not initialized. Run \n\tgit submodule update --init --recursive\n within the repository") endif() +# Enable LTO for release builds +if(NOT CMAKE_BUILD_TYPE MATCHES Debug) + include(CheckIPOSupported) + check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT IPO_ERROR) + + if(IPO_SUPPORTED) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + message(STATUS "IPO / LTO enabled") + else() + message(STATUS "IPO / LTO not supported: <${IPO_ERROR}>") + endif() +endif() + add_executable(ect main.cpp gztools.cpp @@ -38,6 +51,11 @@ add_executable(ect::ect ALIAS ect) if(MINGW) add_compile_options($<$:-mno-ms-bitfields>) add_compile_options($<$:-mno-ms-bitfields>) + + # Ensure static linkage. + target_link_options(ect PRIVATE -static -static-libgcc -static-libstdc++) + set(CMAKE_LINK_SEARCH_START_STATIC TRUE) + set(CMAKE_LINK_SEARCH_END_STATIC TRUE) endif() if(NOT MSVC) @@ -45,6 +63,17 @@ if(NOT MSVC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wno-sign-compare -Wno-unused -Wno-unused-parameter") endif() +if(WIN32) + # Add a manifest. On Windows, this will enable proper handling of Unicode paths, + # as well as paths longer than 260 characters. It also configures UAC handling. + target_sources(ect PRIVATE ect.manifest.rc) + + # Disable MSVC's automatic manifest generation since we provide our own. + if(MSVC) + target_link_options(ect PRIVATE "/MANIFEST:NO") + endif() +endif() + # Use -Ofast in release builds # TODO: This is now deprecated in clang and likely makes little difference, switch back to -O3. foreach(var CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELWITHDEBINFO) @@ -124,9 +153,16 @@ endif() # Enable ZLIB_CONST for everything add_definitions(-DZLIB_CONST) -# Ensure that zlib target points to our custom zlib zlib -set(ZLIB_ROOT "zlib/") -find_package(ZLIB) +# Set CMake variables so that other libraries like libpng and mozjpeg +# can find our custom zlib when calling find_package(ZLIB REQUIRED). +# find_package() fails (at configuration time) otherwise because the +# zlib static library object doesn't exist until build time. +set(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/zlib/") +set(ZLIB_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/zlib") +# ZLIB_LIBRARY needs to be set to where the built library will end up +set(ZLIB_LIBRARY "zlib/${CMAKE_STATIC_LIBRARY_PREFIX}zlib${CMAKE_STATIC_LIBRARY_SUFFIX}") +# Now this check should pass +find_package(ZLIB REQUIRED) option(ECT_MULTITHREADING "Enable multithreaded processing support" ON) option(ECT_MP3_SUPPORT "Enable MP3 support (not currently working)" OFF) diff --git a/src/LzFind.c b/src/LzFind.c index 98d0ac6..25be119 100755 --- a/src/LzFind.c +++ b/src/LzFind.c @@ -24,7 +24,7 @@ void MatchFinder_Create(CMatchFinder *p) } p->son = p->hash + LZFIND_HASH_SIZE; - memset(p->hash, 0, LZFIND_HASH_SIZE * sizeof(unsigned)); + memset(p->hash, 0, LZFIND_HASH_SIZE * sizeof(UInt32)); p->cyclicBufferPos = 0; p->pos = ZOPFLI_WINDOW_SIZE; } @@ -173,7 +173,8 @@ static unsigned short * GetMatches2(UInt32 lenLimit, UInt32 curMatch, UInt32 pos len0 = rle_len; } unsigned char ref_byte = *cur; - unsigned starter = *(unsigned*)(cur - 1); + uint32_t starter; + memcpy(&starter, cur - 1, sizeof(starter)); uint64_t starter_full = (uint64_t)starter + (((uint64_t)starter) << 32); const unsigned char* min = pos > 65535 ? cur - 32767 : cur - (pos - 32768); @@ -229,7 +230,10 @@ static unsigned short * GetMatches2(UInt32 lenLimit, UInt32 curMatch, UInt32 pos const unsigned char* _min = min; unsigned cnt = 0; if (_min < pb - (rle_len - len)) {_min = pb - (rle_len - len);} - while (rle_pos > _min && *(uint64_t*)(rle_pos - 8) == starter_full) {rle_pos-=8; cnt+=8;} + while (rle_pos > _min && memcmp(rle_pos - 8, &starter_full, sizeof(starter_full)) == 0) { + rle_pos-=8; + cnt+=8; + } if (cnt) { if (cnt + len > rle_len - 1) {cnt = rle_len - 1 - len;} curMatch_rle -= cnt; @@ -314,7 +318,7 @@ static void SkipMatches2(UInt32 *son, UInt32 _cyclicBufferPos) #ifdef __SSE4_2__ #include "nmmintrin.h" -#define HASH(cur) unsigned v = 0xffffff & *(const unsigned*)cur; UInt32 hashValue = _mm_crc32_u32(0, v) & LZFIND_HASH_MASK; +#define HASH(cur) unsigned v; memcpy(&v, cur, sizeof(v)); v &= 0xffffff; UInt32 hashValue = _mm_crc32_u32(0, v) & LZFIND_HASH_MASK; #else #define HASH(cur) UInt32 hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ crc[cur[1]]) & LZFIND_HASH_MASK; #endif diff --git a/src/ect.manifest b/src/ect.manifest new file mode 100644 index 0000000..966207b --- /dev/null +++ b/src/ect.manifest @@ -0,0 +1,16 @@ + + + + + + + + + + + + UTF-8 + true + + + diff --git a/src/ect.manifest.rc b/src/ect.manifest.rc new file mode 100644 index 0000000..2703c7c --- /dev/null +++ b/src/ect.manifest.rc @@ -0,0 +1,2 @@ +#include +1 RT_MANIFEST "ect.manifest" diff --git a/src/main.cpp b/src/main.cpp index ff1b2dd..6f45d09 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -549,9 +549,11 @@ int main(int argc, const char * argv[]) { std::vector args; int files = 0; if (argc >= 2){ + bool positional_only_mode = false; for (int i = 1; i < argc; i++) { int strlen = strnlen(argv[i], 64); //File names may be longer and are unaffected by this check - if (strncmp(argv[i], "-", 1) != 0){ + if (!positional_only_mode && strcmp(argv[i], "--") == 0) {positional_only_mode = true;} + else if (positional_only_mode || strncmp(argv[i], "-", 1) != 0){ args.push_back(i); files++; } diff --git a/src/main.h b/src/main.h index 85459ff..f84b63c 100755 --- a/src/main.h +++ b/src/main.h @@ -9,13 +9,16 @@ #include #include #include +#include #include //Compile support for folder input. Requires std::filesystem introduced in C++17. -#if __cplusplus >= 201703L +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L && _MSC_VER >= 1913) +#if __has_include() #define FS_SUPPORTED #include #endif +#endif struct ECTOptions{ unsigned Mode; diff --git a/src/zopfli/match.h b/src/zopfli/match.h index a88ff5e..2870b5c 100644 --- a/src/zopfli/match.h +++ b/src/zopfli/match.h @@ -17,13 +17,24 @@ */ #include +#if defined(__GNUC__) || defined(__clang__) + #define _RESTRICT __restrict__ +#elif defined(_MSC_VER) + #define _RESTRICT __restrict +#else + #define _RESTRICT +#endif + #ifdef __GNUC__ __attribute__ ((always_inline, hot)) +#elif defined(_MSC_VER) +__forceinline #endif -static inline const unsigned char* GetMatch(const unsigned char* __restrict__ scan, - const unsigned char* __restrict__ match, - const unsigned char* __restrict__ end +static inline const unsigned char* GetMatch(const unsigned char* _RESTRICT scan, + const unsigned char* _RESTRICT match, + const unsigned char* _RESTRICT end , const unsigned char* safe_end) { +#undef _RESTRICT #ifdef __GNUC__ /* Optimized Function based on cloudflare's zlib fork. * Note that this may read up to 15 bytes beyond end,