diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b5843531..e3990991 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,3 +77,83 @@ jobs: # test hmp (cd bmf/hml/tests/data && ./gen.sh $(pwd)/../../../../output/files) (cd bmf/hml/tests && pytest) + + build_and_test_win: + name: build and test win + runs-on: windows-2022 + steps: + - uses: actions/checkout@v4 + - name: build_test + shell: pwsh + run: | + $bashPath = "C:\msys64\usr\bin\bash.exe" + + $bashCommand = @' + export PATH=/usr/bin:/usr/lib:/usr/local/bin:/usr/local/lib:$PATH + python -V + python3 -V + echo $PATH + echo "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" | sed 's/[^0-9A-Za-z]/^&/g' + eval "$(./win_env/vcvarsall.sh x64)" + export INCLUDE="${INCLUDE};C:\\msys64\\usr\\local\\include" + wget https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2024-03-20-13-14/ffmpeg-n4.4.4-92-g01fc3034ee-win64-gpl-shared-4.4.zip + pacman -S unzip --noconfirm + unzip ffmpeg-n4.4.4-92-g01fc3034ee-win64-gpl-shared-4.4.zip + mkdir -p /usr/local + cp -r ffmpeg-n4.4.4-92-g01fc3034ee-win64-gpl-shared-4.4/* /usr/local/ + ls /usr/lib + ls /usr/include + ls /usr/bin + cmake -version + ./build_win_lite.sh --msvc=2022 --preset=x64-Release bmf_ffmpeg + cmake --build build_win_lite/x64-Release --config Release --target ALL_BUILD + cmake --build build_win_lite/x64-Release --config Release --target ALL_BUILD + cmake --build build_win_lite/x64-Release --config Release --target ALL_BUILD + cp -r build_win_lite/x64-Release/output . + python -m pip install timeout_decorator numpy onnxruntime pytest opencv-python + export PYTHONHOME="$(dirname "$(which python)")" + export C_INCLUDE_PATH=${C_INCLUDE_PATH}:$(pwd)/output/bmf/include + export CPLUS_INCLUDE_PATH=${CPLUS_INCLUDE_PATH}:$(pwd)/output/bmf/include + export LIBRARY_PATH=${LIBRARY_PATH}:$(pwd)/output/bmf/lib + export PYTHONPATH=$(pwd)/output/bmf/lib:$(pwd)/output + export PATH=$(pwd)/3rd_party/win_rootfs/x64/usr/bin:$(pwd)/3rd_party/win_rootfs/x64/usr/lib:$(pwd)/output/bmf/bin:$(pwd)/output/bmf/lib:${PATH} + echo $PATH + echo $(pwd) + export HMP_TEST_DATA_ROOT=$(pwd)/bmf/hml/tests/data + run_bmf_graph + ffmpeg + module_manager + ./output/bmf/bin/module_manager install python_copy_module python my_module:my_module $(pwd)/output/test/customize_module v0.0.1 + ./output/bmf/bin/module_manager install cpp_copy_module c++ copy_module:CopyModule $(pwd)/output/test/c_module/lib v0.0.1 + (cd output && wget https://github.com/BabitMF/bmf/releases/download/files/files.tar.gz && tar xvf files.tar.gz && rm -rf files.tar.gz) + (cd output && wget https://github.com/BabitMF/bmf/releases/download/files/models.tar.gz && tar xvf models.tar.gz && rm -rf models.tar.gz) + cd output/bmf/bin + ./test_bmf_module_sdk.exe + ./test_bmf_engine.exe --gtest_filter=-go_module.module_loader + ./test_cpp_builder.exe + cd - + export + ls output/bmf/lib + ls output/bmf/bin + which python + which python3 + (cd output/demo/transcode && python test_transcode.py) + (cd output/demo/edit && python test_edit.py) + (cd output/demo/predict && python predict_sample.py) + (cd output/test/audio_copy && python test_simple.py) + (cd output/test/pre_module && python test_pre_module.py) + (cd output/test/sync_mode && python test_sync_mode.py) + (cd output/test/generator && python test_generator.py) + (cd output/test/run_by_config && python test_run_by_config.py) + (cd output/test/server && python test_server.py) + (cd output/test/c_module && python test_video_c_module.py) + (cd output/test/dynamical_graph && python dynamical_graph.py) + (cd output/test/av_log_buffer && python test_av_log_buffer.py) + (cd output/test/push_data_into_graph && python test_push_data.py) + (cd output/test/complex_edit_case && python test_complex_case.py) + (cd output/test/complex_edit_case && python test_compare_with_edit.py) + (cd bmf/hml/tests/data && ./gen.sh $(pwd)/../../../../output/files) + (cd bmf/hml/tests && python -m pytest) + '@ + + echo $bashCommand | & $bashPath \ No newline at end of file diff --git a/bmf/sdk/cpp_sdk/include/bmf/sdk/audio_frame.h b/bmf/sdk/cpp_sdk/include/bmf/sdk/audio_frame.h index c253c06d..a9ad3b32 100644 --- a/bmf/sdk/cpp_sdk/include/bmf/sdk/audio_frame.h +++ b/bmf/sdk/cpp_sdk/include/bmf/sdk/audio_frame.h @@ -23,7 +23,7 @@ namespace bmf_sdk { struct AudioChannelLayout { // ref: ffmpeg/channel_layout.h - enum Layout { + enum Layout : uint64_t { kFRONT_LEFT = 0x00000001, kFRONT_RIGHT = 0x00000002, kFRONT_CENTER = 0x00000004, diff --git a/bmf/sdk/cpp_sdk/src/audio_frame.cpp b/bmf/sdk/cpp_sdk/src/audio_frame.cpp index 07aeb548..143ef4e2 100644 --- a/bmf/sdk/cpp_sdk/src/audio_frame.cpp +++ b/bmf/sdk/cpp_sdk/src/audio_frame.cpp @@ -29,7 +29,7 @@ static int popcount_c(uint32_t x) { } static inline int popcount64_c(uint64_t x) { - return popcount_c(uint32_t(x)) + popcount_c((uint32_t(x >> 32))); + return popcount_c((uint32_t)(x)) + popcount_c((uint32_t)(x >> 32)); } struct AudioFrame::Private { diff --git a/bmf/sdk/cpp_sdk/test/test_module_manager.cpp b/bmf/sdk/cpp_sdk/test/test_module_manager.cpp index 3208abd8..8e66f6a3 100644 --- a/bmf/sdk/cpp_sdk/test/test_module_manager.cpp +++ b/bmf/sdk/cpp_sdk/test/test_module_manager.cpp @@ -38,7 +38,16 @@ TEST(module_manager, test_compat_path) { auto p1 = p0 / std::string("a.out"); p0 /= std::string("a.out"); EXPECT_EQ(p0.string(), p0.string()); - EXPECT_EQ(p0.string(), "/home/foo/a.out"); + std::string p0_result; + std::string val; + #ifdef _WIN32 + p0_result = "/home/foo\\a.out"; + val = "test_bmf_module_sdk.exe"; + #else + p0_result = "/home/foo/a.out"; + val = "test_bmf_module_sdk"; + #endif + EXPECT_EQ(p0.string(), p0_result); auto p2 = fs::path("./foo/b.txt"); EXPECT_EQ(p2.extension(), std::string(".txt")); @@ -56,8 +65,8 @@ TEST(module_manager, test_compat_path) { EXPECT_EQ(p4.parent_path().filename().string(), "foo"); EXPECT_EQ(fs::path("foo").filename().string(), "foo"); - EXPECT_TRUE(fs::exists("test_bmf_module_sdk")); - EXPECT_FALSE(fs::is_directory("test_bmf_module_sdk")); + EXPECT_TRUE(fs::exists(val)); + EXPECT_FALSE(fs::is_directory(val)); EXPECT_FALSE(fs::exists("not_exists")); } @@ -72,7 +81,13 @@ TEST(module_manager, resolve_module_info) { ASSERT_TRUE(info != nullptr); EXPECT_EQ(info->module_name, "c_ffmpeg_decoder"); EXPECT_TRUE(fs::exists(info->module_path)); - EXPECT_EQ(info->module_entry, "libbuiltin_modules.CFFDecoder"); + std::string module_entry; + #ifdef _WIN32 + module_entry = "builtin_modules.CFFDecoder"; + #else + module_entry = "libbuiltin_modules.CFFDecoder"; + #endif + EXPECT_EQ(info->module_entry, module_entry); EXPECT_EQ(info->module_type, "c++"); } @@ -82,7 +97,13 @@ TEST(module_manager, resolve_module_info) { ASSERT_TRUE(info != nullptr); EXPECT_EQ(info->module_name, "pass_through"); EXPECT_TRUE(fs::exists(info->module_path)); - EXPECT_EQ(info->module_entry, "libpass_through.PassThroughModule"); + std::string module_entry; + #ifdef _WIN32 + module_entry = "pass_through.PassThroughModule"; + #else + module_entry = "libpass_through.PassThroughModule"; + #endif + EXPECT_EQ(info->module_entry, module_entry); EXPECT_EQ(info->module_type, "c++"); } @@ -104,7 +125,13 @@ TEST(module_manager, resolve_module_info) { EXPECT_EQ(info->module_type, "c++"); EXPECT_EQ(info->module_name, "cpp_copy_module"); EXPECT_TRUE(fs::exists(info->module_path)); - EXPECT_EQ(info->module_entry, "libcopy_module.CopyModule"); + std::string module_entry; + #ifdef _WIN32 + module_entry = "copy_module.CopyModule"; + #else + module_entry = "libcopy_module.CopyModule"; + #endif + EXPECT_EQ(info->module_entry, module_entry); } // resolve module info from sys repo(python) @@ -170,7 +197,7 @@ TEST(module_manager, load_module) { auto module = facotry->make(1); EXPECT_TRUE(module != nullptr); } - +#ifndef _WIN32 // load sys repo module(go) { auto facotry = M.load_module("go_copy_module"); @@ -178,6 +205,7 @@ TEST(module_manager, load_module) { auto module = facotry->make(1); EXPECT_TRUE(module != nullptr); } +#endif } #endif // BMF_ENABLE_MOBILE diff --git a/bmf/test/complex_edit_case/test_compare_with_edit.py b/bmf/test/complex_edit_case/test_compare_with_edit.py index 0990acd8..6887b740 100644 --- a/bmf/test/complex_edit_case/test_compare_with_edit.py +++ b/bmf/test/complex_edit_case/test_compare_with_edit.py @@ -26,7 +26,7 @@ def jobv(index): input = "../../files/edit" + str(index) + ".mp4" output = "../../files/vv_" + str(index) + ".mp4" cmd = "ffmpeg -y -i " + input + " -t 10.0 -filter_complex " \ - "'[0:v]scale=-2:720,setsar=r=1/1[s],[s]pad=w=1280:h=720:x=(ow-iw)/2:y=(oh-ih)/2:color=black,setsar=r=1/1' " \ + "\"[0:v]scale=-2:720,setsar=r=1/1[s],[s]pad=w=1280:h=720:x=(ow-iw)/2:y=(oh-ih)/2:color=black,setsar=r=1/1\" " \ "-c:v libx264 -crf 23 -preset veryfast -r 20.0 -an -y " + output os.system(cmd) @@ -35,7 +35,7 @@ def longvideo_jobv(index): input = "../../files/edit2.mp4" output = "../../files/vv_" + str(index) + ".mp4" cmd = "ffmpeg -y -i " + input + " -t 60.0 -filter_complex " \ - "'[0:v]scale=-2:720,setsar=r=1/1[s],[s]pad=w=1280:h=720:x=(ow-iw)/2:y=(oh-ih)/2:color=black,setsar=r=1/1' " \ + "\"[0:v]scale=-2:720,setsar=r=1/1[s],[s]pad=w=1280:h=720:x=(ow-iw)/2:y=(oh-ih)/2:color=black,setsar=r=1/1\" " \ "-c:v libx264 -crf 23 -preset veryfast -r 20.0 -an -y " + output os.system(cmd) @@ -156,12 +156,12 @@ def test_edit_concat_ffmpeg(self): i.join() cmd4 = "ffmpeg -y -i ../../files/vv_1.mp4 -i ../../files/vv_2.mp4 -i ../../files/vv_3.mp4 -filter_complex " \ - "'[0:v]scale=1280:720[v1];[v1]split[sp1][sp2];[sp1]trim=start=0:duration=10[v2];[v2]setpts=PTS-STARTPTS[v3];[sp2]trim=start=9:duration=1[v4];" \ + "\"[0:v]scale=1280:720[v1];[v1]split[sp1][sp2];[sp1]trim=start=0:duration=10[v2];[v2]setpts=PTS-STARTPTS[v3];[sp2]trim=start=9:duration=1[v4];" \ "[v4]setpts=PTS-STARTPTS[v5];[v5]scale=200:200[v6];[1:v]scale=1280:720[v7];[v7]split[sp3][sp4];[sp3]trim=start=0:duration=10[v8];" \ "[v8]setpts=PTS-STARTPTS[v9];[v9][v6]overlay=repeatlast=0[v10];[sp4]trim=start=9:duration=1[v11];" \ "[v11]setpts=PTS-STARTPTS[v12];[v12]scale=200:200[v13];[2:v]scale=1280:720[v14];[v14]trim=start=0:duration=10[v15];" \ "[v15]setpts=PTS-STARTPTS[v16];[v16][v13]overlay=repeatlast=0[v17];[v3][v10][v17]concat=n=3:v=1:a=0[v18]" \ - "' -map '[v18]' -c:v libx264 -crf 23 -r 20 -s 1280x720 -preset veryfast %s" % (output_path) + "\" -map \"[v18]\" -c:v libx264 -crf 23 -r 20 -s 1280x720 -preset veryfast %s" % (output_path) os.system(cmd4) @@ -281,12 +281,12 @@ def test_longvideo_edit_concat_ffmpeg(self): i.join() cmd4 = "ffmpeg -y -i ../../files/vv_1.mp4 -i ../../files/vv_2.mp4 -i ../../files/vv_3.mp4 -filter_complex " \ - "'[0:v]scale=1280:720[v1];[v1]split[sp1][sp2];[sp1]trim=start=0:duration=60[v2];[v2]setpts=PTS-STARTPTS[v3];[sp2]trim=start=55:duration=5[v4];" \ + "\"[0:v]scale=1280:720[v1];[v1]split[sp1][sp2];[sp1]trim=start=0:duration=60[v2];[v2]setpts=PTS-STARTPTS[v3];[sp2]trim=start=55:duration=5[v4];" \ "[v4]setpts=PTS-STARTPTS[v5];[v5]scale=200:200[v6];[1:v]scale=1280:720[v7];[v7]split[sp3][sp4];[sp3]trim=start=0:duration=60[v8];" \ "[v8]setpts=PTS-STARTPTS[v9];[v9][v6]overlay=repeatlast=0[v10];[sp4]trim=start=55:duration=5[v11];" \ "[v11]setpts=PTS-STARTPTS[v12];[v12]scale=200:200[v13];[2:v]scale=1280:720[v14];[v14]trim=start=0:duration=60[v15];" \ "[v15]setpts=PTS-STARTPTS[v16];[v16][v13]overlay=repeatlast=0[v17];[v3][v10][v17]concat=n=3:v=1:a=0[v18]" \ - "' -map '[v18]' -c:v libx264 -crf 23 -r 20 -s 1280x720 -preset veryfast %s" % (output_path) + "\" -map \"[v18]\" -c:v libx264 -crf 23 -r 20 -s 1280x720 -preset veryfast %s" % (output_path) os.system(cmd4) diff --git a/bmf/test/cpp_builder/cpp_module.cpp b/bmf/test/cpp_builder/cpp_module.cpp index 338e3f1e..ae8bc39d 100644 --- a/bmf/test/cpp_builder/cpp_module.cpp +++ b/bmf/test/cpp_builder/cpp_module.cpp @@ -55,11 +55,16 @@ TEST(cpp_modules, module_cpp) { nlohmann::json decode_para = { {"input_path", "../../files/big_bunny_10s_30fps.mp4"}}; auto video = graph.Decode(bmf_sdk::JsonParam(decode_para)); - + std::string module_name; + #ifdef _WIN32 + module_name = "../lib/copy_module.dll"; + #else + module_name = "../lib/libcopy_module.so"; + #endif auto video_2 = graph.Module({video["video"]}, "copy_module", bmf::builder::CPP, bmf_sdk::JsonParam(), "CopyModule", - "../lib/libcopy_module.so", "copy_module:CopyModule"); + module_name, "copy_module:CopyModule"); nlohmann::json encode_para = { {"output_path", output_file}, diff --git a/build_win_lite.sh b/build_win_lite.sh index 21922b7e..d5881b93 100755 --- a/build_win_lite.sh +++ b/build_win_lite.sh @@ -11,6 +11,7 @@ BUILD_DIR=build_win_lite OUTPUT_DIR=output COMPILE_ARCH="" preset="" +PYTHON_VERSION=3.9 export SCRIPT_EXEC_MODE=win export WIN_XCOMPILE_ROOT=$(pwd)/3rd_party/win_rootfs @@ -117,6 +118,7 @@ if [[ ${HOST} =~ msys_nt || ${HOST} =~ mingw ]]; then -DRUN_HAVE_POSIX_REGEX=0 \ -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ -DBMF_BUILD_VERSION=${BMF_BUILD_VERSION} \ + -DBMF_PYENV=${PYTHON_VERSION} \ -DBMF_BUILD_COMMIT=${BMF_BUILD_COMMIT} ../.. ) diff --git a/cmake/ffmpeg.cmake b/cmake/ffmpeg.cmake index eeaf50b4..c6326f29 100644 --- a/cmake/ffmpeg.cmake +++ b/cmake/ffmpeg.cmake @@ -41,7 +41,6 @@ function(find_ffmpeg_version FFMPEG_VERSION_INCLUDE_DIR VERSION_VAR) endif() endfunction() - if(DEFINED ENV{FFMPEG_ROOT_PATH}) set(FFMPEG_LIBRARY_DIR $ENV{FFMPEG_ROOT_PATH}/lib) set(FFMPEG_INCLUDE_DIR $ENV{FFMPEG_ROOT_PATH}/include) @@ -52,7 +51,7 @@ else() find_library(FFMPEG_LIBRARY_DIR avcodec HINTS /usr/) endif() - +message(STATUS "FFMPEG_INCLUDE_DIR:" ${FFMPEG_INCLUDE_DIR} ", FFMPEG_LIBRARY_DIR:" ${FFMPEG_LIBRARY_DIR}) if(FFMPEG_LIBRARY_DIR AND FFMPEG_INCLUDE_DIR) message(STATUS "find FFmpeg, FFMPEG_INCLUDE_DIR:" ${FFMPEG_INCLUDE_DIR} ", FFMPEG_LIBRARY_DIR:" ${FFMPEG_LIBRARY_DIR}) function(define_ffmpeg_target) diff --git a/win_env/vcvarsall.sh b/win_env/vcvarsall.sh new file mode 100644 index 00000000..4da835c7 --- /dev/null +++ b/win_env/vcvarsall.sh @@ -0,0 +1,317 @@ +set -x +#!/usr/bin/env bash +# +# Source: https://github.com/nathan818fr/vcvars-bash +# Author: Nathan Poirier +# +set -Eeuo pipefail +shopt -s inherit_errexit + +function detect_platform() { + case "${OSTYPE:-}" in + cygwin* | msys* | win32) + declare -gr bash_platform='win_cyg' + ;; + *) + if [[ -n "${WSL_DISTRO_NAME:-}" ]]; then + declare -gr bash_platform='win_wsl' + else + printf 'error: Unsupported platform (%s)\n' "${OSTYPE:-}" >&2 + printf 'hint: This script only supports Bash on Windows (Git Bash, WSL, etc.)\n' >&2 + return 1 + fi + ;; + esac +} + +function detect_mode() { + # Detect the mode depending on the name called + if [[ "$(basename -- "$0")" == vcvarsrun* ]]; then + declare -gr script_mode='run' # vcvarsrun.sh + else + declare -gr script_mode='default' # vcvarsall.sh + fi +} + +function print_usage() { + case "$script_mode" in + default) + cat </dev/null || true; } | fix_crlf | sed '/^Syntax:/d; s/^ vcvarsall.bat //')" +} + +function main() { + detect_platform + detect_mode + + # Parse arguments + if [[ $# -eq 0 ]]; then + print_usage >&2 + return 1 + fi + + local arg vcvarsall_args=() + for arg in "$@"; do + shift + if [[ "$arg" == '--' ]]; then + if [[ "$script_mode" == 'default' ]]; then + printf 'error: Unexpected argument: --\n' >&2 + printf 'hint: Use vcvarsrun to run a command\n' >&2 + return 1 + fi + break + fi + vcvarsall_args+=("$(cmdesc "$arg")") + done + + if [[ "$script_mode" == 'run' && $# -eq 0 ]]; then + printf 'error: No command specified\n' >&2 + return 1 + fi + + # Get MSVC environment variables from vcvarsall.bat + local vcvarsall vcvarsall_env + vcvarsall=$(find_vcvarsall) + vcvarsall_env=$({ cmd "$(cmdesc "$vcvarsall")" "${vcvarsall_args[@]}" '&&' 'set' &2 + continue + fi + + case "${name^^}" in + LIB | LIBPATH | INCLUDE | EXTERNAL_INCLUDE | COMMANDPROMPTTYPE | DEVENVDIR | EXTENSIONSDKDIR | FRAMEWORK* | \ + PLATFORM | PREFERREDTOOLARCHITECTURE | UCRT* | UNIVERSALCRTSDK* | VCIDE* | VCINSTALL* | VCPKG* | VCTOOLS* | \ + VSCMD* | VSINSTALL* | VS[0-9]* | VISUALSTUDIO* | WINDOWSLIB* | WINDOWSSDK*) + export_env "$name" "$value" + ;; + PATH) + # PATH is a special case, requiring special handling + local new_paths + new_paths=$(pathlist_win_to_unix "$value") # Convert to unix-style path list + new_paths=$(pathlist_normalize "${PATH}:${new_paths}") # Prepend the current PATH + export_env 'WINDOWS_PATH' "$value" + export_env 'PATH' "$new_paths" + ;; + esac + done <<<"$vcvarsall_env" + + if [[ "$initialized" == 'false' ]]; then + printf 'error: vcvarsall.bat failed' >&2 + return 1 + fi + + # Execute command if needed + if [[ "$script_mode" == 'run' ]]; then + exec "$@" + fi +} + +# Locate vcvarsall.bat +# Inputs: +# VSINSTALLDIR: The path to the Visual Studio installation directory (optional) +# Outputs: +# stdout: The windows-style path to vcvarsall.bat +function find_vcvarsall() { + local vsinstalldir + if [[ -n "${VSINSTALLDIR:-}" ]]; then + vsinstalldir="$VSINSTALLDIR" + else + local vswhere + vswhere=$(command -v 'vswhere' 2>/dev/null || unixpath 'C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe') + vsinstalldir=$("$vswhere" -latest -property installationPath &2 + return 1 + fi + fi + + printf '%s\n' "$(winpath "$vsinstalldir")\\VC\\Auxiliary\\Build\\vcvarsall.bat" +} + +# Run a command with cmd.exe +# Inputs: +# $@: The command string to run (use cmdesc to escape arguments when needed) +# Outputs: +# stdout: The cmd.exe standard output +# stderr: The cmd.exe error output +function cmd() { + # This seems to work fine on all supported platforms + # (even with all the weird path and argument conversions on MSYS-like) + MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*' cmd.exe /s /c " ; $* " +} + +# Escape a cmd.exe command argument +# Inputs: +# $1: The argument to escape +# Outputs: +# stdout: The escaped argument +function cmdesc() { + # shellcheck disable=SC2001 + sed 's/[^0-9A-Za-z]/^&/g' <<<"$1" +} + +# Convert path to an absolute unix-style path +# Inputs: +# $1: The path to convert +# Outputs: +# stdout: The converted path +function unixpath() { + local path=$1 + case "$bash_platform" in + win_wsl) + case "$path" in + [a-zA-Z]:\\* | [a-zA-Z]:/* | \\\\* | //*) + # Convert windows path using wslpath (unix mode, absolute path) + wslpath -u -a -- "$path" + ;; + *) + # Convert unix path using realpath + realpath -m -- "$path" + ;; + esac + ;; + *) + cygpath -u -a -- "$path" + ;; + esac +} + +# Convert path to an absolute windows-style path +# Inputs: +# $1: The path to convert +# Outputs: +# stdout: The converted path +function winpath() { + local path=$1 + case "$bash_platform" in + win_wsl) + case "$path" in + [a-zA-Z]:\\* | [a-zA-Z]:/* | \\\\* | //*) + # Already a windows path + printf '%s' "$path" + ;; + *) + # Convert using wslpath (windows mode, absolute path) + wslpath -w -a -- "$path" + ;; + esac + ;; + *) + # Convert using cygpath (windows mode, absolute path, long form) + cygpath -w -a -l -- "$path" + ;; + esac +} + +# Convert a windows-style path list to a unix-style path list +# Inputs: +# $1: The windows-style path list to convert +# Outputs: +# stdout: The converted unix-style path list +function pathlist_win_to_unix() { + local win_paths=$1 + + local path_dir first=true + while IFS= read -r -d';' path_dir; do + if [[ -z "$path_dir" ]]; then continue; fi + + if [[ "$first" == 'true' ]]; then first=false; else printf ':'; fi + printf '%s' "$(unixpath "$path_dir")" + done <<<"${win_paths};" +} + +# Normalize a unix-style path list, removing duplicates and empty entries +# Inputs: +# $1: The list to normalize +# Outputs: +# stdout: The normalized path list +function pathlist_normalize() { + local unix_paths=$1 + + declare -A seen_paths + local path_dir first=true + while IFS= read -r -d ':' path_dir; do + if [[ -z "$path_dir" ]]; then continue; fi + if [[ -n "${seen_paths[$path_dir]:-}" ]]; then continue; fi + seen_paths[$path_dir]=1 + + if [[ "$first" == 'true' ]]; then first=false; else printf ':'; fi + printf '%s' "$path_dir" + done <<<"${unix_paths}:" +} + +# Convert CRLF to LF +# Inputs: +# stdin: The input to convert +# Outputs: +# stdout: The converted input +function fix_crlf() { + sed 's/\r$//' +} + +eval 'main "$@";exit "$?"' diff --git a/win_env/vcvarsrun.sh b/win_env/vcvarsrun.sh new file mode 100644 index 00000000..d27164eb --- /dev/null +++ b/win_env/vcvarsrun.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +# This file should have been a symbolic link, but it's not always supported on Windows. +# shellcheck source=vcvarsall.sh +source -- "$(dirname -- "$0")/vcvarsall.sh"