Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
b0545ab
Select backend devices via arg
stduhpf Jan 9, 2026
f89620c
fix build
stduhpf Jan 9, 2026
61af83e
show backend device description
stduhpf Jan 11, 2026
c8ffbd3
CLI: add --list-devices arg
stduhpf Jan 11, 2026
4e7bdb3
null-terminate even if buffer is too small
stduhpf Jan 15, 2026
53d32a9
move stuff to ggml_extend.cpp
stduhpf Jan 16, 2026
1800c9a
--upscaler-backend-device
stduhpf Jan 16, 2026
c1fc286
use diffusion_backend for loading LoRAs
stduhpf Jan 16, 2026
9de5032
--photomaker-backend-device (+fixes)
stduhpf Jan 16, 2026
a85121f
--vision-backend-device
stduhpf Jan 16, 2026
4d0b24f
check backends at runtime
Jan 21, 2026
ead7116
fix missing includes
Jan 21, 2026
4597013
fix typo
Jan 23, 2026
10763be
multiple clip backend devices
Jan 25, 2026
f3076ea
update help message
stduhpf Jan 28, 2026
a97a978
Add RPC documentation
stduhpf Jan 28, 2026
20e6ba4
update docs
stduhpf Jan 28, 2026
970304e
update RPC docs
stduhpf Jan 28, 2026
a792579
fix apply_loras_immediately when using different non-CPU backends
stduhpf Jan 29, 2026
9e3229b
Force sequencial tensor loading when using RPC
stduhpf Feb 16, 2026
61ed023
fix build
stduhpf Mar 1, 2026
8fe2ccc
Get first stage backend for loading loras
stduhpf Mar 19, 2026
ae5b8ab
Fix lora loading when using multiple clip backends
stduhpf Mar 19, 2026
229664d
rm all head code for ggml
Cyberhan123 Mar 26, 2026
e302ee5
feat: enhance the build system by adding CMake configuration and back…
Cyberhan123 Mar 26, 2026
83f7bab
fix review
Cyberhan123 Mar 26, 2026
1556395
format code
Cyberhan123 Mar 26, 2026
1428dc1
up date ci job
Cyberhan123 Mar 26, 2026
1cf3edc
fix vision_backend null
Cyberhan123 Mar 26, 2026
4e5471c
rm -j args
Cyberhan123 Mar 26, 2026
7783b32
test ci
Cyberhan123 Mar 26, 2026
3d392a1
fix: remove trailing backslashes in CMake commands
Cyberhan123 Mar 26, 2026
2579bb1
add cpu on
Cyberhan123 Mar 28, 2026
19bc8e2
add rpc and cpu on docker
Cyberhan123 Mar 28, 2026
3e07a2b
try fix ci
Cyberhan123 Mar 28, 2026
54f2762
add ggml-cpu.h
Cyberhan123 Mar 28, 2026
17db074
fix use cpu backend
Cyberhan123 Mar 28, 2026
7b5d14f
fix sycl docker build
Cyberhan123 Mar 28, 2026
755ee89
Add a Windows ROCm job to use tarball distribution of TheRock
superm1 Feb 14, 2026
dbea191
Update HIP target to use 26.Q1 (ROCm 7.1.1)
superm1 Feb 14, 2026
f246d83
update rocm new build
Cyberhan123 Mar 28, 2026
29576a3
sync and update rocm build
Cyberhan123 Mar 28, 2026
ef54ba4
fix and add ccache
Cyberhan123 Mar 28, 2026
1e23dd4
fix rocm build
Cyberhan123 Mar 28, 2026
5ff332b
fix rocm cache path
Cyberhan123 Mar 28, 2026
9f4fc8d
add ninja_job
Cyberhan123 Mar 28, 2026
355dcda
rm -j params
Cyberhan123 Mar 28, 2026
ca6c96d
fix cr
Cyberhan123 Mar 28, 2026
1a31a23
format code
Cyberhan123 Mar 28, 2026
e4d143b
fix version backend
Cyberhan123 Mar 28, 2026
8c8f2d0
format code
Cyberhan123 Mar 28, 2026
0527541
fix hard_code with SD_USE_VULKAN
Cyberhan123 Mar 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
303 changes: 150 additions & 153 deletions .github/workflows/build.yml

Large diffs are not rendered by default.

184 changes: 112 additions & 72 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ if (NOT XCODE AND NOT MSVC AND NOT CMAKE_BUILD_TYPE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")

if (MSVC)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
add_compile_definitions(_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING)
Expand All @@ -22,61 +24,85 @@ else()
set(SD_STANDALONE OFF)
endif()

if (MINGW)
set(BUILD_SHARED_LIBS_DEFAULT OFF)
else()
set(BUILD_SHARED_LIBS_DEFAULT ON)
endif()

option(BUILD_SHARED_LIBS "build shared libraries" ${BUILD_SHARED_LIBS_DEFAULT})

if (WIN32)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
endif()

if (MSVC)
add_compile_options("$<$<COMPILE_LANGUAGE:C>:/utf-8>")
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/utf-8>")
add_compile_options("$<$<COMPILE_LANGUAGE:C>:/bigobj>")
add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/bigobj>")
endif()

if (SD_STANDALONE)
# enable parallel builds for msbuild
list(APPEND CMAKE_VS_GLOBALS UseMultiToolTask=true)
list(APPEND CMAKE_VS_GLOBALS EnforceProcessCountAcrossBuilds=true)
endif()


#
# Option list
#

# general
#option(SD_BUILD_TESTS "sd: build tests" ${SD_STANDALONE})
option(SD_BUILD_EXAMPLES "sd: build examples" ${SD_STANDALONE})
option(SD_CUDA "sd: cuda backend" OFF)
option(SD_HIPBLAS "sd: rocm backend" OFF)
option(SD_METAL "sd: metal backend" OFF)
option(SD_VULKAN "sd: vulkan backend" OFF)
option(SD_OPENCL "sd: opencl backend" OFF)
option(SD_SYCL "sd: sycl backend" OFF)
option(SD_MUSA "sd: musa backend" OFF)
option(SD_BUILD_SHARED_LIBS "sd: build shared libs" OFF)
option(SD_BUILD_SHARED_GGML_LIB "sd: build ggml as a separate shared lib" OFF)
option(SD_USE_SYSTEM_GGML "sd: use system-installed GGML library" OFF)
#option(SD_BUILD_SERVER "sd: build server example" ON)

if(SD_CUDA)
message("-- Use CUDA as backend stable-diffusion")
set(GGML_CUDA ON)
add_definitions(-DSD_USE_CUDA)
endif()
# Required for relocatable CMake package
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/build-info.cmake)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/common.cmake)

if(SD_METAL)
message("-- Use Metal as backend stable-diffusion")
set(GGML_METAL ON)
add_definitions(-DSD_USE_METAL)
if (NOT DEFINED SD_BUILD_NUMBER)
set(SD_BUILD_NUMBER ${BUILD_NUMBER})
endif()
if (NOT DEFINED SD_BUILD_COMMIT)
set(SD_BUILD_COMMIT ${BUILD_COMMIT})
endif()
set(SD_INSTALL_VERSION 0.0.${SD_BUILD_NUMBER})

if (SD_VULKAN)
message("-- Use Vulkan as backend stable-diffusion")
set(GGML_VULKAN ON)
add_definitions(-DSD_USE_VULKAN)
endif ()

if (SD_OPENCL)
message("-- Use OpenCL as backend stable-diffusion")
set(GGML_OPENCL ON)
add_definitions(-DSD_USE_OPENCL)
endif ()

if (SD_HIPBLAS)
message("-- Use HIPBLAS as backend stable-diffusion")
set(GGML_HIP ON)
add_definitions(-DSD_USE_CUDA)
endif ()
# override ggml options
set(GGML_ALL_WARNINGS ${SD_ALL_WARNINGS})
set(GGML_FATAL_WARNINGS ${SD_FATAL_WARNINGS})

if(SD_MUSA)
message("-- Use MUSA as backend stable-diffusion")
set(GGML_MUSA ON)
add_definitions(-DSD_USE_CUDA)
if (NOT DEFINED GGML_CUDA_GRAPHS)
set(GGML_CUDA_GRAPHS_DEFAULT ON)
endif()

# Ref: https://github.com/ggml-org/llama.cpp/blob/master/CMakeLists.txt#L145
# transition helpers
function (sd_option_depr TYPE OLD)
if (${OLD})
set(NEW "${ARGV2}")
if(NEW)
message(${TYPE} "${OLD} is deprecated, use ${NEW} instead")
set(${NEW} ON PARENT_SCOPE)
else()
message(${TYPE} "${OLD} is deprecated and will be ignored")
endif()
endif()
endfunction()

sd_option_depr(FATAL_ERROR SD_HIPBLAS GGML_HIP)
sd_option_depr(FATAL_ERROR SD_BUILD_SHARED_LIBS BUILD_SHARED_LIBS)
sd_option_depr(FATAL_ERROR SD_BUILD_SHARED_GGML_LIB BUILD_SHARED_LIBS)
sd_option_depr(WARNING SD_CUDA GGML_CUDA)
sd_option_depr(WARNING SD_METAL GGML_METAL)
sd_option_depr(WARNING SD_VULKAN GGML_VULKAN)
sd_option_depr(WARNING SD_OPENCL GGML_OPENCL)
sd_option_depr(WARNING SD_SYCL GGML_SYCL)
sd_option_depr(WARNING SD_MUSA GGML_MUSA)

set(SD_LIB stable-diffusion)

file(GLOB SD_LIB_SOURCES
Expand Down Expand Up @@ -119,29 +145,9 @@ set_property(
SDCPP_BUILD_COMMIT=${SDCPP_BUILD_COMMIT} SDCPP_BUILD_VERSION=${SDCPP_BUILD_VERSION}
)

if(SD_BUILD_SHARED_LIBS)
message("-- Build shared library")
message(${SD_LIB_SOURCES})
if(NOT SD_BUILD_SHARED_GGML_LIB)
set(BUILD_SHARED_LIBS OFF)
endif()
add_library(${SD_LIB} SHARED ${SD_LIB_SOURCES})
add_definitions(-DSD_BUILD_SHARED_LIB)
target_compile_definitions(${SD_LIB} PRIVATE -DSD_BUILD_DLL)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
else()
message("-- Build static library")
if(NOT SD_BUILD_SHARED_GGML_LIB)
set(BUILD_SHARED_LIBS OFF)
endif()
add_library(${SD_LIB} STATIC ${SD_LIB_SOURCES})
endif()

if(SD_SYCL)
message("-- Use SYCL as backend stable-diffusion")
set(GGML_SYCL ON)
# Is this needed?
if(GGML_SYCL)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-narrowing -fsycl")
add_definitions(-DSD_USE_SYCL)
# disable fast-math on host, see:
# https://www.intel.com/content/www/us/en/docs/cpp-compiler/developer-guide-reference/2021-10/fp-model-fp.html
if (WIN32)
Expand All @@ -150,7 +156,7 @@ if(SD_SYCL)
set(SYCL_COMPILE_OPTIONS -fp-model=precise)
endif()
message("-- Turn off fast-math for host in SYCL backend")
target_compile_options(${SD_LIB} PRIVATE ${SYCL_COMPILE_OPTIONS})
list(APPEND SD_TARGET_PRIVATE_COMPILE_OPTIONS ${SYCL_COMPILE_OPTIONS})
endif()

set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
Expand All @@ -175,18 +181,52 @@ if (NOT TARGET ggml)
endif()

add_subdirectory(thirdparty)

target_link_libraries(${SD_LIB} PUBLIC ggml zip)
target_include_directories(${SD_LIB} PUBLIC . include)
target_include_directories(${SD_LIB} PUBLIC . thirdparty)
target_compile_features(${SD_LIB} PUBLIC c_std_11 cxx_std_17)

add_subdirectory(src)

if (SD_BUILD_EXAMPLES)
add_subdirectory(examples)
endif()

set(SD_PUBLIC_HEADERS include/stable-diffusion.h)
set_target_properties(${SD_LIB} PROPERTIES PUBLIC_HEADER "${SD_PUBLIC_HEADERS}")
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

set(SD_INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE PATH "Location of header files")
set(SD_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR} CACHE PATH "Location of library files")
set(SD_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR} CACHE PATH "Location of binary files")
set(SD_PUBLIC_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/include/stable-diffusion.h
)

install(TARGETS ${SD_LIB} LIBRARY PUBLIC_HEADER)
set_target_properties(${SD_LIB}
PROPERTIES
PUBLIC_HEADER "${SD_PUBLIC_HEADERS}")

install(TARGETS ${SD_LIB}
RUNTIME DESTINATION ${SD_BIN_INSTALL_DIR}
LIBRARY DESTINATION ${SD_LIB_INSTALL_DIR}
ARCHIVE DESTINATION ${SD_LIB_INSTALL_DIR}
PUBLIC_HEADER DESTINATION ${SD_INCLUDE_INSTALL_DIR})

configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/sd-config.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/sd-config.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sd
PATH_VARS SD_INCLUDE_INSTALL_DIR
SD_LIB_INSTALL_DIR
SD_BIN_INSTALL_DIR )

write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/sd-version.cmake
VERSION ${SD_INSTALL_VERSION}
COMPATIBILITY SameMajorVersion)

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/sd-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/sd-version.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/sd)

configure_file(cmake/sd.pc.in
"${CMAKE_CURRENT_BINARY_DIR}/sd.pc"
@ONLY)

install(FILES "${CMAKE_CURRENT_BINARY_DIR}/sd.pc"
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
2 changes: 1 addition & 1 deletion Dockerfile.cuda
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ WORKDIR /sd.cpp
COPY . .

ARG CUDACXX=/usr/local/cuda/bin/nvcc
RUN cmake . -B ./build -DSD_CUDA=ON
RUN cmake . -B ./build -DGGML_CUDA=ON -DGGML_RPC=ON -DCMAKE_EXE_LINKER_FLAGS=-Wl,--allow-shlib-undefined
RUN cmake --build ./build --config Release -j$(nproc)

FROM nvidia/cuda:${CUDA_VERSION}-cudnn-runtime-ubuntu${UBUNTU_VERSION} AS runtime
Expand Down
3 changes: 2 additions & 1 deletion Dockerfile.musa
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
ARG MUSA_VERSION=rc4.2.0
ARG UBUNTU_VERSION=22.04

FROM mthreads/musa:${MUSA_VERSION}-devel-ubuntu${UBUNTU_VERSION}-amd64 as build

Check warning on line 4 in Dockerfile.musa

View workflow job for this annotation

GitHub Actions / Build and push container images (musa)

The 'as' keyword should match the case of the 'from' keyword

FromAsCasing: 'as' and 'FROM' keywords' casing do not match More info: https://docs.docker.com/go/dockerfile/rule/from-as-casing/

RUN apt-get update && apt-get install -y ccache cmake git

Expand All @@ -13,10 +13,11 @@
cmake .. -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_FLAGS="${CMAKE_C_FLAGS} -fopenmp -I/usr/lib/llvm-14/lib/clang/14.0.0/include -L/usr/lib/llvm-14/lib" \
-DCMAKE_CXX_FLAGS="${CMAKE_CXX_FLAGS} -fopenmp -I/usr/lib/llvm-14/lib/clang/14.0.0/include -L/usr/lib/llvm-14/lib" \
-DSD_MUSA=ON -DCMAKE_BUILD_TYPE=Release && \
-DGGML_MUSA=ON -DGGML_RPC=ON -DCMAKE_BUILD_TYPE=Release && \

cmake --build . --config Release

Check warning on line 18 in Dockerfile.musa

View workflow job for this annotation

GitHub Actions / Build and push container images (musa)

Empty continuation lines will become errors in a future release

NoEmptyContinuation: Empty continuation line More info: https://docs.docker.com/go/dockerfile/rule/no-empty-continuation/

FROM mthreads/musa:${MUSA_VERSION}-runtime-ubuntu${UBUNTU_VERSION}-amd64 as runtime

Check warning on line 20 in Dockerfile.musa

View workflow job for this annotation

GitHub Actions / Build and push container images (musa)

The 'as' keyword should match the case of the 'from' keyword

FromAsCasing: 'as' and 'FROM' keywords' casing do not match More info: https://docs.docker.com/go/dockerfile/rule/from-as-casing/

COPY --from=build /sd.cpp/build/bin/sd-cli /sd-cli
COPY --from=build /sd.cpp/build/bin/sd-server /sd-server
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.sycl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ WORKDIR /sd.cpp
COPY . .

RUN mkdir build && cd build && \
cmake .. -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DSD_SYCL=ON -DCMAKE_BUILD_TYPE=Release && \
cmake .. -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DGGML_SYCL=ON -DGGML_RPC=ON -DCMAKE_BUILD_TYPE=Release && \
cmake --build . --config Release -j$(nproc)

FROM intel/oneapi-basekit:${SYCL_VERSION}-devel-ubuntu24.04 AS runtime
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile.vulkan
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ WORKDIR /sd.cpp

COPY . .

RUN cmake . -B ./build -DSD_VULKAN=ON
RUN cmake . -B ./build -DGGML_VULKAN=ON -DGGML_RPC=ON
RUN cmake --build ./build --config Release --parallel

FROM ubuntu:$UBUNTU_VERSION AS runtime
Expand Down
48 changes: 48 additions & 0 deletions cmake/build-info.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
set(BUILD_NUMBER 0)
set(BUILD_COMMIT "unknown")
set(BUILD_COMPILER "unknown")
set(BUILD_TARGET "unknown")

# Look for git
find_package(Git)
if(NOT Git_FOUND)
find_program(GIT_EXECUTABLE NAMES git git.exe)
if(GIT_EXECUTABLE)
set(Git_FOUND TRUE)
message(STATUS "Found Git: ${GIT_EXECUTABLE}")
else()
message(WARNING "Git not found. Build info will not be accurate.")
endif()
endif()

# Get the commit count and hash
if(Git_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE HEAD
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RES
)
if (RES EQUAL 0)
set(BUILD_COMMIT ${HEAD})
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} rev-list --count HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE COUNT
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RES
)
if (RES EQUAL 0)
set(BUILD_NUMBER ${COUNT})
endif()
endif()

set(BUILD_COMPILER "${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION}")

if(CMAKE_VS_PLATFORM_NAME)
set(BUILD_TARGET ${CMAKE_VS_PLATFORM_NAME})
else()
set(BUILD_TARGET "${CMAKE_SYSTEM_NAME} ${CMAKE_SYSTEM_PROCESSOR}")
endif()
60 changes: 60 additions & 0 deletions cmake/common.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
include("ggml/cmake/common.cmake")

# https://github.com/ggml-org/llama.cpp/blob/master/cmake/common.cmake

function(sd_add_compile_flags)
if (SD_FATAL_WARNINGS)
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
list(APPEND C_FLAGS -Werror)
list(APPEND CXX_FLAGS -Werror)
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_compile_options(/WX)
endif()
endif()

if (SD_ALL_WARNINGS)
if (NOT MSVC)
list(APPEND C_FLAGS -Wshadow -Wstrict-prototypes -Wpointer-arith -Wmissing-prototypes
-Werror=implicit-int -Werror=implicit-function-declaration)

list(APPEND CXX_FLAGS -Wmissing-declarations -Wmissing-noreturn)

list(APPEND WARNING_FLAGS -Wall -Wextra -Wpedantic -Wcast-qual -Wno-unused-function)

list(APPEND C_FLAGS ${WARNING_FLAGS})
list(APPEND CXX_FLAGS ${WARNING_FLAGS})

ggml_get_flags(${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION})

add_compile_options("$<$<COMPILE_LANGUAGE:C>:${C_FLAGS};${GF_C_FLAGS}>"
"$<$<COMPILE_LANGUAGE:CXX>:${CXX_FLAGS};${GF_CXX_FLAGS}>")
else()
# todo : msvc
set(C_FLAGS "" PARENT_SCOPE)
set(CXX_FLAGS "" PARENT_SCOPE)
endif()
endif()

if (NOT MSVC)
if (SD_SANITIZE_THREAD)
message(STATUS "Using -fsanitize=thread")

add_compile_options(-fsanitize=thread)
link_libraries (-fsanitize=thread)
endif()

if (SD_SANITIZE_ADDRESS)
message(STATUS "Using -fsanitize=address")

add_compile_options(-fsanitize=address -fno-omit-frame-pointer)
link_libraries (-fsanitize=address)
endif()

if (SD_SANITIZE_UNDEFINED)
message(STATUS "Using -fsanitize=undefined")

add_compile_options(-fsanitize=undefined)
link_libraries (-fsanitize=undefined)
endif()
endif()
endfunction()
Loading
Loading