From f27be28abb1215b9e8a13919a85dd842d2b07fca Mon Sep 17 00:00:00 2001 From: s1lentq Date: Thu, 25 Mar 2021 07:19:15 +0700 Subject: [PATCH] CMakeLists.txt: Configure for more compat to older linux distros (Debian 7, Centoc 6 etc) --- .github/workflows/build.yml | 17 +++++ dep/bzip2/CMakeLists.txt | 4 +- rehlds/CMakeLists.txt | 11 ++- rehlds/HLTV/Console/CMakeLists.txt | 11 ++- rehlds/HLTV/Core/CMakeLists.txt | 11 ++- rehlds/HLTV/DemoPlayer/CMakeLists.txt | 7 +- rehlds/HLTV/Director/CMakeLists.txt | 5 +- rehlds/HLTV/Director/src/Director.cpp | 11 +-- rehlds/HLTV/Proxy/CMakeLists.txt | 13 ++-- rehlds/HLTV/common/DirectorCmd.cpp | 4 +- rehlds/HLTV/common/DirectorCmd.h | 2 +- rehlds/dedicated/CMakeLists.txt | 11 ++- rehlds/engine/sys_dll.cpp | 14 ++++ .../FileSystem_Stdio/CMakeLists.txt | 5 ++ rehlds/version/glibc_test.sh | 71 +++++++++++++++++++ 15 files changed, 172 insertions(+), 25 deletions(-) create mode 100755 rehlds/version/glibc_test.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a02c29f..4d89f67 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -117,6 +117,23 @@ jobs: mv build/rehlds/HLTV/Director/director.so publish/bin/linux32/valve/dlls/director.so mv build/rehlds/filesystem/FileSystem_Stdio/filesystem_stdio.so publish/bin/linux32/filesystem_stdio.so + - name: Run GLIBC/ABI version compat test + run: | + binaries=( + "publish/bin/linux32/engine_i486.so" + "publish/bin/linux32/hlds_linux" + "publish/bin/linux32/hltv" + "publish/bin/linux32/core.so" + "publish/bin/linux32/proxy.so" + "publish/bin/linux32/demoplayer.so" + "publish/bin/linux32/valve/dlls/director.so" + "publish/bin/linux32/filesystem_stdio.so" + ) + bash ./rehlds/version/glibc_test.sh ${binaries[@]} + if [[ $? -ne 0 ]]; then + exit 1 # Assertion failed + fi + - name: Deploy artifacts uses: actions/upload-artifact@v2 id: upload-job diff --git a/dep/bzip2/CMakeLists.txt b/dep/bzip2/CMakeLists.txt index 74f4b99..841ed41 100644 --- a/dep/bzip2/CMakeLists.txt +++ b/dep/bzip2/CMakeLists.txt @@ -1,6 +1,8 @@ cmake_minimum_required(VERSION 3.1) project(bzip2 C) +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g0 -O1 -fno-stack-protector") + set(BZIP2_SRCS "src/blocksort.c" "src/bzlib.c" @@ -18,4 +20,4 @@ include_directories( ) add_library(bzip2 STATIC ${BZIP2_SRCS}) -set_target_properties(bzip2 PROPERTIES COMPILE_FLAGS "-m32" POSITION_INDEPENDENT_CODE ON) +set_target_properties(bzip2 PROPERTIES COMPILE_FLAGS "-m32") diff --git a/rehlds/CMakeLists.txt b/rehlds/CMakeLists.txt index 33c5d1f..9c0bf35 100644 --- a/rehlds/CMakeLists.txt +++ b/rehlds/CMakeLists.txt @@ -17,7 +17,7 @@ elseif (USE_CLANG_COMPILER) set(CMAKE_CXX_COMPILER "/usr/bin/clang++") endif() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-rtti -fno-exceptions") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-rtti -fno-plt -fno-exceptions") # Remove noxref code and data set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffunction-sections -fdata-sections") @@ -34,7 +34,7 @@ if (USE_INTEL_COMPILER) if (NOT DEBUG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ipo") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -ipo") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -ipo") endif() else() # Produce code optimized for the most common IA32/AMD64/EM64T processors. @@ -55,6 +55,10 @@ else() endif() endif() +if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcf-protection=none") +endif() + if (NOT DEBUG AND USE_STATIC_LIBSTDC) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-gc-sections -Wl,--version-script=\"${PROJECT_SOURCE_DIR}/../version_script.lds\"") endif() @@ -127,6 +131,7 @@ add_definitions( -D_LINUX -DLINUX -D_GLIBCXX_USE_CXX11_ABI=0 + -U_FORTIFY_SOURCE -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -D_strdup=strdup @@ -147,6 +152,6 @@ endif() add_library(engine SHARED ${appversion.sh} ${ENGINE_SRCS} ${COMMON_SRCS} ${PUBLIC_SRCS}) set_property(TARGET engine PROPERTY LIBRARY_OUTPUT_NAME engine_i486) -set_target_properties(engine PROPERTIES PREFIX "" COMPILE_FLAGS "-m32" LINK_FLAGS "-m32" POSITION_INDEPENDENT_CODE ON) +set_target_properties(engine PROPERTIES PREFIX "" COMPILE_FLAGS "-m32" LINK_FLAGS "-m32" POSITION_INDEPENDENT_CODE OFF) target_link_libraries(engine dl rt m aelf32 bzip2 steam_api) add_dependencies(engine appversion) diff --git a/rehlds/HLTV/Console/CMakeLists.txt b/rehlds/HLTV/Console/CMakeLists.txt index b6253bb..80a8e8f 100644 --- a/rehlds/HLTV/Console/CMakeLists.txt +++ b/rehlds/HLTV/Console/CMakeLists.txt @@ -40,9 +40,17 @@ if (USE_INTEL_COMPILER) else() # Produce code optimized for the most common IA32/AMD64/EM64T processors. # As new processors are deployed in the marketplace, the behavior of this option will change. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3 -flto\ + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3\ -fpermissive -fno-sized-deallocation\ -Wno-unused-result -Wno-unknown-pragmas -Wno-write-strings") + + if (NOT USE_CLANG_COMPILER AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-stringop-truncation -Wno-format-truncation") + endif() +endif() + +if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcf-protection=none") endif() set(PROJECT_SRC_DIR @@ -86,6 +94,7 @@ add_definitions( -D_LINUX -DLINUX -D_GLIBCXX_USE_CXX11_ABI=0 + -U_FORTIFY_SOURCE -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -D_strdup=strdup diff --git a/rehlds/HLTV/Core/CMakeLists.txt b/rehlds/HLTV/Core/CMakeLists.txt index e969086..0fbdb9a 100644 --- a/rehlds/HLTV/Core/CMakeLists.txt +++ b/rehlds/HLTV/Core/CMakeLists.txt @@ -35,16 +35,24 @@ if (USE_INTEL_COMPILER) else() # Produce code optimized for the most common IA32/AMD64/EM64T processors. # As new processors are deployed in the marketplace, the behavior of this option will change. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3 -flto\ + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3\ -fpermissive -fno-sized-deallocation\ -Wno-unused-result -Wno-unknown-pragmas -Wno-unused-variable\ -Wno-sign-compare -Wno-write-strings -Wno-strict-aliasing") if (USE_CLANG_COMPILER) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-private-field") + else() + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-stringop-truncation -Wno-format-truncation") + endif() endif() endif() +if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcf-protection=none") +endif() + set(PROJECT_SRC_DIR "${PROJECT_SOURCE_DIR}/src" "${PROJECT_SOURCE_DIR}/../" @@ -105,6 +113,7 @@ add_definitions( -D_LINUX -DLINUX -D_GLIBCXX_USE_CXX11_ABI=0 + -U_FORTIFY_SOURCE -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -D_strdup=strdup diff --git a/rehlds/HLTV/DemoPlayer/CMakeLists.txt b/rehlds/HLTV/DemoPlayer/CMakeLists.txt index 819e50f..3161e1d 100644 --- a/rehlds/HLTV/DemoPlayer/CMakeLists.txt +++ b/rehlds/HLTV/DemoPlayer/CMakeLists.txt @@ -35,12 +35,16 @@ if (USE_INTEL_COMPILER) else() # Produce code optimized for the most common IA32/AMD64/EM64T processors. # As new processors are deployed in the marketplace, the behavior of this option will change. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3 -flto\ + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3\ -fpermissive -fno-sized-deallocation\ -Wno-unused-result -Wno-unknown-pragmas\ -Wno-sign-compare -Wno-write-strings -Wno-strict-aliasing") endif() +if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcf-protection=none") +endif() + set(PROJECT_SRC_DIR "${PROJECT_SOURCE_DIR}/src" "${PROJECT_SOURCE_DIR}/../" @@ -84,6 +88,7 @@ add_definitions( -D_LINUX -DLINUX -D_GLIBCXX_USE_CXX11_ABI=0 + -U_FORTIFY_SOURCE -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -D_strdup=strdup diff --git a/rehlds/HLTV/Director/CMakeLists.txt b/rehlds/HLTV/Director/CMakeLists.txt index a390f0f..fa7264f 100644 --- a/rehlds/HLTV/Director/CMakeLists.txt +++ b/rehlds/HLTV/Director/CMakeLists.txt @@ -35,14 +35,14 @@ if (USE_INTEL_COMPILER) else() # Produce code optimized for the most common IA32/AMD64/EM64T processors. # As new processors are deployed in the marketplace, the behavior of this option will change. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3 -flto\ + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3\ -fpermissive -fno-sized-deallocation\ -Wno-unused-result -Wno-unknown-pragmas\ -Wno-write-strings -Wno-strict-aliasing") endif() if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--wrap=expf") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcf-protection=none") endif() set(PROJECT_SRC_DIR @@ -90,6 +90,7 @@ add_definitions( -D_LINUX -DLINUX -D_GLIBCXX_USE_CXX11_ABI=0 + -U_FORTIFY_SOURCE -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -D_strdup=strdup diff --git a/rehlds/HLTV/Director/src/Director.cpp b/rehlds/HLTV/Director/src/Director.cpp index 0b7448d..a9c8262 100644 --- a/rehlds/HLTV/Director/src/Director.cpp +++ b/rehlds/HLTV/Director/src/Director.cpp @@ -40,14 +40,9 @@ EXPOSE_SINGLE_INTERFACE(Director, IDirector, DIRECTOR_INTERFACE_VERSION); // Building go on GCC 8.3 or greater that have newest expf GLIBC.2.27 than // available on the destination virtual machine, so we can downgrade GLIBC version // for this function. -// Use for linker: -Wl,--wrap=expf +// NOTE: This workaround seem not compatible with -flto compile GCC option. -extern int expf(int __fd, int __cmd, ...); __asm__(".symver expf,expf@GLIBC_" GLIBC_expf_VERSION); -DLL_EXPORT float __wrap_expf(float x) -{ - return expf(x); -} #endif // #if defined(_WIN32) @@ -389,9 +384,9 @@ float Director::AddBestGenericCut() int seqNrMod = m_nextCutSeqnr % m_historyLength; float sumTarget2Rank[MAX_CLIENTS]; - float bestTarget2Rank, bestRank = 0; + float bestTarget2Rank, bestRank = 0.0f; float targetRankSum = 0; - int newTarget, newTarget2; + int newTarget = 0, newTarget2 = 0; int bestTarget2; for (int i = 0; i < MAX_CLIENTS; i++) diff --git a/rehlds/HLTV/Proxy/CMakeLists.txt b/rehlds/HLTV/Proxy/CMakeLists.txt index 00466cd..69653f4 100644 --- a/rehlds/HLTV/Proxy/CMakeLists.txt +++ b/rehlds/HLTV/Proxy/CMakeLists.txt @@ -16,7 +16,7 @@ elseif (USE_CLANG_COMPILER) set(CMAKE_CXX_COMPILER "/usr/bin/clang++") endif() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-exceptions") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fno-plt -fno-exceptions") if (DEBUG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g3 -O3 -ggdb") @@ -30,23 +30,27 @@ if (USE_INTEL_COMPILER) if (NOT DEBUG) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ipo") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -ipo") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -ipo") endif() else() # Produce code optimized for the most common IA32/AMD64/EM64T processors. # As new processors are deployed in the marketplace, the behavior of this option will change. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3 -flto\ + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3\ -fpermissive -fno-sized-deallocation\ -Wno-unused-result -Wno-unknown-pragmas -Wno-unused-variable\ -Wno-write-strings -Wno-strict-aliasing") if (USE_CLANG_COMPILER) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-private-field") + else() + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-stringop-truncation -Wno-format-truncation") + endif() endif() endif() if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--wrap=expf") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcf-protection=none") endif() set(PROJECT_SRC_DIR @@ -112,6 +116,7 @@ add_definitions( -D_LINUX -DLINUX -D_GLIBCXX_USE_CXX11_ABI=0 + -U_FORTIFY_SOURCE -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -D_strdup=strdup diff --git a/rehlds/HLTV/common/DirectorCmd.cpp b/rehlds/HLTV/common/DirectorCmd.cpp index 6ee3de1..2f8e32c 100644 --- a/rehlds/HLTV/common/DirectorCmd.cpp +++ b/rehlds/HLTV/common/DirectorCmd.cpp @@ -583,7 +583,7 @@ void DirectorCmd::WriteToStream(BitBuffer *stream) } } -char *DirectorCmd::ToString() +const char *DirectorCmd::ToString() { int i1, i2, i3; float f1, f2, f3, f4; @@ -592,7 +592,7 @@ char *DirectorCmd::ToString() char *t1 = m_CMD_Name[m_Type]; char t2[1024]; - static char s[1024]; + static char s[2048]; Q_memset(s, 0, sizeof(s)); switch (m_Type) diff --git a/rehlds/HLTV/common/DirectorCmd.h b/rehlds/HLTV/common/DirectorCmd.h index 88e5101..3d25af7 100644 --- a/rehlds/HLTV/common/DirectorCmd.h +++ b/rehlds/HLTV/common/DirectorCmd.h @@ -40,7 +40,7 @@ public: void Copy(DirectorCmd *cmd); void Resize(int size); void FromString(char *string); - char *ToString(); + const char *ToString(); void WriteToStream(BitBuffer *stream); bool ReadFromStream(BitBuffer *stream); int GetType(); diff --git a/rehlds/dedicated/CMakeLists.txt b/rehlds/dedicated/CMakeLists.txt index 808159c..1ee3e93 100644 --- a/rehlds/dedicated/CMakeLists.txt +++ b/rehlds/dedicated/CMakeLists.txt @@ -40,9 +40,17 @@ if (USE_INTEL_COMPILER) else() # Produce code optimized for the most common IA32/AMD64/EM64T processors. # As new processors are deployed in the marketplace, the behavior of this option will change. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3 -flto\ + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mtune=generic -msse3\ -fpermissive -fno-sized-deallocation\ -Wno-unused-result") + + if (NOT USE_CLANG_COMPILER AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-stringop-truncation -Wno-format-truncation") + endif() +endif() + +if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcf-protection=none") endif() set(PROJECT_SRC_DIR @@ -87,6 +95,7 @@ add_definitions( -D_LINUX -DLINUX -D_GLIBCXX_USE_CXX11_ABI=0 + -U_FORTIFY_SOURCE -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -D_strdup=strdup diff --git a/rehlds/engine/sys_dll.cpp b/rehlds/engine/sys_dll.cpp index add30da..507f51c 100644 --- a/rehlds/engine/sys_dll.cpp +++ b/rehlds/engine/sys_dll.cpp @@ -597,6 +597,20 @@ double EXT_FUNC Sys_FloatTime(void) #else // not _WIN32 +#if __GNUC__ >= 8 + +#define GLIBC_clock_gettime_VERSION "2.2" + +// +// Building go on GCC 8.3 or greater that have newest clock_gettime GLIBC.2.17 than +// available on the destination virtual machine, so we can downgrade GLIBC version +// for this function. +// NOTE: This workaround seem not compatible with -flto compile GCC option. + +__asm__(".symver clock_gettime,clock_gettime@GLIBC_" GLIBC_clock_gettime_VERSION); + +#endif // #if __GNUC__ >= 8 + double Sys_FloatTime(void) { static struct timespec start_time; diff --git a/rehlds/filesystem/FileSystem_Stdio/CMakeLists.txt b/rehlds/filesystem/FileSystem_Stdio/CMakeLists.txt index 72b486e..52f3a96 100644 --- a/rehlds/filesystem/FileSystem_Stdio/CMakeLists.txt +++ b/rehlds/filesystem/FileSystem_Stdio/CMakeLists.txt @@ -51,6 +51,10 @@ foreach(f ${WRAP_FUNCS_LIST}) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-wrap,${f}") endforeach() +if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcf-protection=none") +endif() + set(PROJECT_SRC_DIR "${PROJECT_SOURCE_DIR}/src" "${PROJECT_SOURCE_DIR}/../.." @@ -80,6 +84,7 @@ add_definitions( -D_LINUX -DLINUX -D_GLIBCXX_USE_CXX11_ABI=0 + -U_FORTIFY_SOURCE -D_strdup=strdup -D_stricmp=strcasecmp -D_strnicmp=strncasecmp diff --git a/rehlds/version/glibc_test.sh b/rehlds/version/glibc_test.sh new file mode 100755 index 0000000..3dc1fbb --- /dev/null +++ b/rehlds/version/glibc_test.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +main() +{ + files=($@) + + declare -A threshold_version + threshold_version[CXXABI]="1.3.5" + threshold_version[GLIBCXX]="3.4.15" + threshold_version[GLIBC]="2.7" + + for k in "${!threshold_version[@]}"; do + for f in "${files[@]}" + do + : + version=$(readelf -sV $f | sed -n 's/.*@'$k'_//p' | sort -u -V | tail -1 | cut -d ' ' -f 1) + if [[ ! -z "$version" ]]; then + check_version_greater $version ${threshold_version[$k]} + if [[ $? -eq 1 ]]; then + echo -e "\033[0;31mAssertion failed:\033[0m Binary \033[0;32m${f}\033[0m has ${k}_\033[0;33m$version\033[0m greater than max version ${k}_\033[0;33m${threshold_version[$k]}\033[0m" + exit -1 + fi + fi + done + + echo -e "[\033[0;32mOK\033[0m] ${k}_\033[0;33m${threshold_version[$k]}\033[0m" + done +} + +check_version_greater() +{ + if [[ -z "$1" || $1 == $2 ]]; then + return 0 + fi + + local IFS=. + local i ver1=($1) ver2=($2) + + # fill empty fields in ver1 with zeros + for ((i = ${#ver1[@]}; i < ${#ver2[@]}; i++)) + do + ver1[i]=0 + done + + for ((i = 0; i < ${#ver1[@]}; i++)) + do + if [[ -z ${ver2[i]} ]] + then + # fill empty fields in ver2 with zeros + ver2[i]=0 + fi + + if ((10#${ver1[i]} > 10#${ver2[i]})) + then + return 1 + fi + + if ((10#${ver1[i]} < 10#${ver2[i]})) + then + break + fi + done + + return 0 +} + +# Initialize +main $* + +# Exit normally +exit 0