Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add bimg #15317

Merged
merged 5 commits into from
Feb 13, 2023
Merged

Add bimg #15317

Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 4 additions & 0 deletions recipes/bimg/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
sources:
"cci.20230114":
url: "https://github.com/bkaradzic/bimg/archive/7afa2419254fd466c013a51bdeb0bee3022619c4.tar.gz"
sha256: "664D2DB41B60E1BEA473898427CD71D43CD33397A24596F1A2CF269D324A305D"
246 changes: 246 additions & 0 deletions recipes/bimg/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
from conan import ConanFile
from conan.tools.files import copy, get, rename
from conan.tools.build import check_min_cppstd
from conan.tools.layout import basic_layout
from conan.tools.microsoft import is_msvc, check_min_vs, is_msvc_static_runtime
from conan.tools.scm import Version
from conan.errors import ConanInvalidConfiguration
from conan.tools.microsoft import MSBuild, VCVars
from conan.tools.gnu import Autotools, AutotoolsToolchain
from conan.tools.env import VirtualBuildEnv
from pathlib import Path
import os

required_conan_version = ">=1.50.0"


class bimgConan(ConanFile):
name = "bimg"
license = "BSD-2-Clause"
homepage = "https://github.com/bkaradzic/bimg"
url = "https://github.com/conan-io/conan-center-index"
description = "Image library providing loading, saving, conversions and other utilities."
topics = ("image", "graphics")
settings = "os", "compiler", "arch", "build_type"
options = {"tools": [True, False]}
default_options = {"tools": False}

@property
def _bx_folder(self):
return "bx"

@property
def _bimg_folder(self):
return "bimg"

@property
def _bimg_path(self):
return os.path.join(self.source_folder, self._bimg_folder)

@property
def _genie_extra(self):
genie_extra = ""
if is_msvc(self) and not is_msvc_static_runtime(self):
genie_extra += " --with-dynamic-runtime"
if self.options.tools:
genie_extra += " --with-tools"
return genie_extra

@property
def _lib_target_prefix(self):
if self.settings.os == "Windows":
return "libs\\"
else:
return ""

@property
def _tool_target_prefix(self):
if self.settings.os == "Windows":
return "tools\\"
else:
return ""

@property
def _projs(self):
projs = [f"{self._lib_target_prefix}bimg", f"{self._lib_target_prefix}bimg_decode", f"{self._lib_target_prefix}bimg_encode"]
if self.options.tools:
projs.extend([f"{self._lib_target_prefix}texturec"])
return projs

@property
def _compiler_required(self):
return {
"gcc": "8",
"clang": "3.3",
"apple-clang": "5",
}

@property
def _bx_version(self): #mapping of bimg version to required/used bx version
return {"cci.20230114": "cci.20221116"}

@property
def _settings_build(self):
return getattr(self, "settings_build", self.settings)

def layout(self):
basic_layout(self, src_folder="src")

def requirements(self):
self.requires(f"bx/{self._bx_version[self.version]}")

def validate(self):
if self.settings.compiler.get_safe("cppstd"):
check_min_cppstd(self, 14)
check_min_vs(self, 191)
if not is_msvc(self):
try:
minimum_required_compiler_version = self._compiler_required[str(self.settings.compiler)]
if Version(self.settings.compiler.version) < minimum_required_compiler_version:
raise ConanInvalidConfiguration("This package requires C++14 support. The current compiler does not support it.")
except KeyError:
self.output.warn("This recipe has no checking for the current compiler. Please consider adding it.")

def build_requirements(self):
self.tool_requires("genie/1170")
if not is_msvc(self) and self._settings_build.os == "Windows":
self.win_bash = True
if not self.conf.get("tools.microsoft.bash:path", check_type=str):
self.tool_requires("msys2/cci.latest")

def source(self):
get(self, **self.conan_data["sources"][self.version], strip_root=True,
destination=os.path.join(self.source_folder, self._bimg_folder))
# bimg's genie project, and the projects generated by it, expect bx source to be present on the same relative root as bimg's in order to build
# usins a pre-built bx instead would require significant changes to the genie project but may be worth looking into in the future
get(self, **self.dependencies["bx"].conan_data["sources"][self._bx_version[self.version]], strip_root=True,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to patch instead and consume bx as package instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be very difficult as the entire build system (genie project) relies on it being that way, and I'm not sure if I'm good enough with genie to modify it to do it that way instead. I could try to play around with doing that but I think it might be too much work (with even more in the future to keep it working) than it would be worth, considering it wouldn't actually affect projects that just use bgfx/bimg/bx and that grabbing bx source from the dependency package when building is easy and straightforward.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember about the discussion using genie in another PR. If say it's very difficult, please, keep doing dual download, but add a comment in the recipe explaining it. So far, this build system is one of most exotics that we have in CCI.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that bimg needs bx source (and bgfx needs bimg and bx source) isn't really genie's fault, but it is how the genie projects for them are set up.
The initial reason was that bx and bimg were basically part of bgfx and they were only split out as separate projects when they started getting bigger, and it was decided to just need their source to make it easy for people to build bgfx (and bimg and bx) without dealing with managing dependencies, just by also cloning bimg and bx in the same place. This was, of course, back when dependency management didn't have many or any good options like conan.
Perhaps in the future this can be changed, maybe even by using conan, but at the moment there aren't really any plans for it upstream. I will add a comment explaining this for now, thanks for the feedback!

destination=os.path.join(self.source_folder, self._bx_folder))

def generate(self):
vbe = VirtualBuildEnv(self)
vbe.generate()
if is_msvc(self):
tc = VCVars(self)
tc.generate()
else:
tc = AutotoolsToolchain(self)
tc.generate()

def build(self):
if is_msvc(self):
# Conan to Genie translation maps
vs_ver_to_genie = {"17": "2022", "16": "2019", "15": "2017",
"193": "2022", "192": "2019", "191": "2017"}

# Use genie directly, then msbuild on specific projects based on requirements
genie_VS = f"vs{vs_ver_to_genie[str(self.settings.compiler.version)]}"
genie_gen = f"{self._genie_extra} {genie_VS}"
self.run(f"genie {genie_gen}", cwd=self._bimg_path)

msbuild = MSBuild(self)
# customize to Release when RelWithDebInfo
msbuild.build_type = "Debug" if self.settings.build_type == "Debug" else "Release"
# use Win32 instead of the default value when building x86
msbuild.platform = "Win32" if self.settings.arch == "x86" else msbuild.platform
msbuild.build(os.path.join(self._bimg_path, ".build", "projects", genie_VS, "bimg.sln"), targets=self._projs)
else:
# Not sure if XCode can be spefically handled by conan for building through, so assume everything not VS is make
# gcc-multilib and g++-multilib required for 32bit cross-compilation, should see if we can check and install through conan

# Conan to Genie translation maps
compiler_str = str(self.settings.compiler)
compiler_and_os_to_genie = {"Windows": f"--gcc=mingw-{compiler_str}", "Linux": f"--gcc=linux-{compiler_str}",
"FreeBSD": "--gcc=freebsd", "Macos": "--gcc=osx",
"Android": "--gcc=android", "iOS": "--gcc=ios"}
gmake_os_to_proj = {"Windows": "mingw", "Linux": "linux", "FreeBSD": "freebsd", "Macos": "osx", "Android": "android", "iOS": "ios"}
gmake_arch_to_genie_suffix = {"x86": "-x86", "x86_64": "-x64", "armv8": "-arm64", "armv7": "-arm"}
os_to_use_arch_config_suffix = {"Windows": False, "Linux": False, "FreeBSD": False, "Macos": True, "Android": True, "iOS": True}

build_type_to_make_config = {"Debug": "config=debug", "Release": "config=release"}
arch_to_make_config_suffix = {"x86": "32", "x86_64": "64"}
os_to_use_make_config_suffix = {"Windows": True, "Linux": True, "FreeBSD": True, "Macos": False, "Android": False, "iOS": False}

# Generate projects through genie
genieGen = f"{self._genie_extra} {compiler_and_os_to_genie[str(self.settings.os)]}"
if os_to_use_arch_config_suffix[str(self.settings.os)]:
genieGen += f"{gmake_arch_to_genie_suffix[str(self.settings.arch)]}"
genieGen += " gmake"
self.run(f"genie {genieGen}", cwd=self._bimg_path)

# Build project folder and path from given settings
projFolder = f"gmake-{gmake_os_to_proj[str(self.settings.os)]}"
if self.settings.os == "Windows" or compiler_str not in ["gcc", "apple-clang"]:
projFolder += f"-{compiler_str}" #mingw-gcc or mingw-clang for windows; -clang for linux (where gcc on linux has no extra)
if os_to_use_arch_config_suffix[str(self.settings.os)]:
projFolder += gmake_arch_to_genie_suffix[str(self.settings.arch)]
proj_path = os.path.sep.join([self._bimg_path, ".build", "projects", projFolder])

# Build make args from settings
conf = build_type_to_make_config[str(self.settings.build_type)]
if os_to_use_make_config_suffix[str(self.settings.os)]:
conf += arch_to_make_config_suffix[str(self.settings.arch)]
if self.settings.os == "Windows":
mingw = "MINGW=$MINGW_PREFIX"
proj_path = proj_path.replace("\\", "/") # Fix path for msys...
else:
mingw = ""
autotools = Autotools(self)
# Build with make
for proj in self._projs:
autotools.make(target=proj, args=["-R", f"-C {proj_path}", mingw, conf])

def package(self):
# Set platform suffixes and prefixes
if self.settings.os == "Windows":
lib_pat = "*bimg*.lib"
package_lib_prefix = ""
elif self.settings.os in ["Linux", "FreeBSD"]:
lib_pat = "*bimg*.a"
package_lib_prefix = "lib"
elif self.settings.os == "Macos":
lib_pat = "*bimg*.a"
package_lib_prefix = "lib"

# Get build bin folder
for bimg_out_dir in os.listdir(os.path.join(self._bimg_path, ".build")):
if not bimg_out_dir=="projects":
build_bin = os.path.join(self._bimg_path, ".build", bimg_out_dir, "bin")
break

# Copy license
copy(self, pattern="LICENSE", dst=os.path.join(self.package_folder, "licenses"), src=self._bimg_path)
# Copy includes
copy(self, pattern="*.h", dst=os.path.join(self.package_folder, "include"), src=os.path.join(self._bimg_path, "include"))
# Copy libs
copy(self, pattern=lib_pat, dst=os.path.join(self.package_folder, "lib"), src=build_bin, keep_path=False)
# Copy tools
if self.options.tools:
copy(self, pattern="texturec*", dst=os.path.join(self.package_folder, "bin"), src=build_bin, keep_path=False)

# Rename for consistency across platforms and configs
for bimg_file in Path(os.path.join(self.package_folder, "lib")).glob("*bimg*"):
fExtra = ""
if bimg_file.name.find("encode") >= 0:
fExtra = "_encode"
elif bimg_file.name.find("decode") >= 0:
fExtra = "_decode"
rename(self, os.path.join(self.package_folder, "lib", bimg_file.name),
os.path.join(self.package_folder, "lib", f"{package_lib_prefix}bimg{fExtra}{bimg_file.suffix}"))
if self.options.tools:
for bimg_file in Path(os.path.join(self.package_folder, "bin")).glob("*texturec*"):
rename(self, os.path.join(self.package_folder, "bin", bimg_file.name),
os.path.join(self.package_folder, "bin", f"texturec{bimg_file.suffix}"))

def package_info(self):
self.cpp_info.includedirs = ["include"]
self.cpp_info.libs = ["bimg_encode", "bimg_decode", "bimg"]

self.cpp_info.set_property("cmake_file_name", "bimg")
self.cpp_info.set_property("cmake_target_name", "bimg::bimg")
self.cpp_info.set_property("pkg_config_name", "bimg")

# TODO: to remove in conan v2 once cmake_find_package_* generators removed
self.cpp_info.filenames["cmake_find_package"] = "bimg"
self.cpp_info.filenames["cmake_find_package_multi"] = "bimg"
self.cpp_info.names["cmake_find_package"] = "bimg"
self.cpp_info.names["cmake_find_package_multi"] = "bimg"
9 changes: 9 additions & 0 deletions recipes/bimg/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.8)

project(test_package LANGUAGES CXX)

find_package(bimg REQUIRED CONFIG)

add_executable(${PROJECT_NAME} test_package.cpp)
set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 14 CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF)
target_link_libraries(${PROJECT_NAME} bimg::bimg)
29 changes: 29 additions & 0 deletions recipes/bimg/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from conan import ConanFile
from conan.tools.build import can_run
from conan.tools.layout import cmake_layout
from conan.tools.cmake import CMake
import os

required_conan_version = ">=1.50.0"

class TestPackageConan(ConanFile):
settings = "os", "arch", "compiler", "build_type"
generators = "CMakeDeps", "CMakeToolchain"
test_type = "explicit"

def layout(self):
cmake_layout(self)

def requirements(self):
self.requires(self.tested_reference_str)

def build(self):
if can_run(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if can_run(self):
bin_path = os.path.join(self.cpp.build.bindirs[0], "test_package")
self.run(bin_path, env="conanrun")
26 changes: 26 additions & 0 deletions recipes/bimg/all/test_package/test_package.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include <bx/bx.h>
#include <bx/allocator.h>
#include <bimg/bimg.h>
#include <bimg/decode.h>

//An embedded 2x2 PNG image in RGB8 format with a red pixel, a green pixel, a blue pixel and a white pixel
const unsigned char img[129] ={0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x02, 0x08, 0x02, 0x00, 0x00, 0x00, 0xfd, 0xd4, 0x9a,
0x73, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47, 0x42, 0x00, 0xae, 0xce,
0x1c, 0xe9, 0x00, 0x00, 0x00, 0x04, 0x67, 0x41, 0x4d, 0x41, 0x00, 0x00,
0xb1, 0x8f, 0x0b, 0xfc, 0x61, 0x05, 0x00, 0x00, 0x00, 0x09, 0x70, 0x48,
0x59, 0x73, 0x00, 0x00, 0x0e, 0xc3, 0x00, 0x00, 0x0e, 0xc3, 0x01, 0xc7,
0x6f, 0xa8, 0x64, 0x00, 0x00, 0x00, 0x16, 0x49, 0x44, 0x41, 0x54, 0x18,
0x57, 0x63, 0x78, 0x2b, 0xa3, 0xa2, 0xb4, 0xd1, 0x87, 0xc1, 0xde, 0xe3,
0xcc, 0xff, 0xff, 0xff, 0x01, 0x24, 0xec, 0x06, 0x9d, 0x64, 0xf4, 0x18,
0xdc, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};

int main() {
bx::DefaultAllocator defAlloc;
bimg::ImageContainer* imageContainer = nullptr;
imageContainer = bimg::imageParse(&defAlloc, (const void*) img, 129 * sizeof(char));
BX_ASSERT(imageContainer->m_format == bimg::TextureFormat::RGB8, "Image incorrectly decoded.")
bimg::imageFree(imageContainer);
return 0;
}
9 changes: 9 additions & 0 deletions recipes/bimg/all/test_v1_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.8)

project(test_package LANGUAGES CXX)

include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)

add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../test_package/
${CMAKE_CURRENT_BINARY_DIR}/test_package/)
17 changes: 17 additions & 0 deletions recipes/bimg/all/test_v1_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from conans import ConanFile, CMake, tools
import os


class BimgTestPackageConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "cmake", "cmake_find_package_multi"

def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if not tools.cross_building(self):
bin_path = os.path.join("bin", "test_package")
self.run(bin_path, run_environment=True)
3 changes: 3 additions & 0 deletions recipes/bimg/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
versions:
"cci.20230114":
folder: all