Skip to content
Merged
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
24 changes: 24 additions & 0 deletions .github/workflows/build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,27 @@ jobs:
- name: Run JS tests
working-directory: packages/tml-js
run: npm test

conan-test:
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: recursive

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install Conan
run: |
pip install conan
conan profile detect

- name: Create and test Conan package
run: conan create packages/tml-cpp --build=missing
20 changes: 11 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -258,17 +258,19 @@ jobs:
pip install conan
conan profile detect

- name: Test Conan package locally
working-directory: packages/tml-cpp
run: |
conan create . --build=missing
- name: Create and test Conan package
run: conan create packages/tml-cpp --build=missing

- name: Prepare Conan Center submission
run: |
echo "Conan package built and tested successfully."
VERSION=$(python3 -c "
import re, pathlib
text = pathlib.Path('packages/tml-cpp/conanfile.py').read_text()
m = re.search(r'version\s*=\s*[\"\']([0-9.]+)[\"\']', text)
print(m.group(1) if m else 'unknown')
")
echo "Conan package textmatelib/${VERSION} built and tested successfully."
echo "To submit to Conan Center:"
echo "1. Fork https://github.com/conan-io/conan-center-index"
echo "2. Add recipe to recipes/textmatelib/"
echo "3. Create PR to conan-center-index"
echo ""
echo "Package version: $(grep 'version =' packages/tml-cpp/conanfile.py | head -1)"
echo "2. Add recipe under recipes/textmatelib/${VERSION}/"
echo "3. Create a PR to conan-center-index"
16 changes: 13 additions & 3 deletions packages/tml-cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ project(tml VERSION 0.1.0 LANGUAGES CXX)

include(GenerateExportHeader)

# Allow callers (e.g. Conan) to override the thirdparty directory.
# Defaults to the monorepo layout where thirdparty/ sits two levels above this file.
if(NOT DEFINED THIRDPARTY_DIR)
set(THIRDPARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty")
endif()

# Set C++17 standard for modern features
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
Expand Down Expand Up @@ -91,7 +97,7 @@ endif()
# Include directories
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/rapidjson/include
${THIRDPARTY_DIR}/rapidjson/include
)

# Source files
Expand Down Expand Up @@ -208,7 +214,7 @@ if(NOT USE_WASM_BUILD)

ExternalProject_Add(
oniguruma
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/oniguruma
SOURCE_DIR ${THIRDPARTY_DIR}/oniguruma
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/oniguruma/build
CMAKE_ARGS ${ONIG_CMAKE_ARGS}
BUILD_COMMAND ${CMAKE_COMMAND} --build . --config ${CMAKE_BUILD_TYPE}
Expand All @@ -225,7 +231,7 @@ else()

ExternalProject_Add(
oniguruma_wasm
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../thirdparty/oniguruma
SOURCE_DIR ${THIRDPARTY_DIR}/oniguruma
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/thirdparty/oniguruma/build_wasm
CMAKE_ARGS
-DCMAKE_BUILD_TYPE=Release
Expand Down Expand Up @@ -385,6 +391,10 @@ install(FILES ${TEXTMATE_HEADERS}
DESTINATION include/tml
)

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/tml_export.h
DESTINATION include/tml
)

# Enable testing (skip for WASM builds and shared library builds)
# Tests should only use the static library version for proper linking
if(NOT USE_WASM_BUILD AND NOT BUILD_SHARED_LIBS)
Expand Down
43 changes: 40 additions & 3 deletions packages/tml-cpp/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class TextMateLibConan(ConanFile):
url = "https://github.com/jbltx/TextMateLib"
description = "TextMate syntax highlighting library - a C++ implementation of TextMate grammar parsing and tokenization"
topics = ("textmate", "syntax", "highlighting", "grammar", "tokenizer", "parsing")
package_type = "library"
settings = "os", "compiler", "build_type", "arch"
options = {
"shared": [True, False],
Expand All @@ -21,11 +22,11 @@ class TextMateLibConan(ConanFile):
"shared": False,
"fPIC": True
}
# Only include sources within this package directory; thirdparty deps are
# handled by export_sources() to avoid Conan 2's restriction on ".." patterns.
exports_sources = (
"CMakeLists.txt",
"src/*",
"../../thirdparty/rapidjson/*",
"../../thirdparty/oniguruma/*"
)

def config_options(self):
Expand All @@ -39,12 +40,35 @@ def configure(self):
def layout(self):
cmake_layout(self)

def export_sources(self):
# Copy vendored thirdparty dependencies (git submodules) from the monorepo
# root into the Conan export-sources folder so that `conan create` works
# without requiring ".." patterns in exports_sources (which Conan 2 rejects).
thirdparty_root = os.path.normpath(
os.path.join(self.recipe_folder, "..", "..", "thirdparty")
)
export_thirdparty = os.path.join(self.export_sources_folder, "thirdparty")
copy(self, "rapidjson/*", src=thirdparty_root, dst=export_thirdparty)
copy(self, "oniguruma/*", src=thirdparty_root, dst=export_thirdparty)

def generate(self):
deps = CMakeDeps(self)
deps.generate()
tc = CMakeToolchain(self)
tc.variables["BUILD_SHARED_LIBS"] = self.options.shared
tc.variables["USE_WASM_BUILD"] = False
# Determine the thirdparty directory. Two cases:
# 1. conan create – thirdparty was exported into source_folder/thirdparty
# 2. conan install (local/monorepo) – thirdparty lives at ../../thirdparty
# relative to the package folder (packages/tml-cpp).
thirdparty_in_source = os.path.join(self.source_folder, "thirdparty")
if os.path.isdir(thirdparty_in_source):
thirdparty_dir = thirdparty_in_source
else:
thirdparty_dir = os.path.normpath(
os.path.join(self.source_folder, "..", "..", "thirdparty")
)
tc.variables["THIRDPARTY_DIR"] = thirdparty_dir.replace("\\", "/")
tc.generate()

def build(self):
Expand All @@ -56,9 +80,22 @@ def package(self):
copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
cmake = CMake(self)
cmake.install()
# Oniguruma is built via ExternalProject_Add and is not part of cmake --install.
# Copy the static library and public headers so that consumers can link all symbols
# (libtml.a has undefined references to onig_* that the consumer's linker must resolve)
# and so that installed headers like onigLib.h (which include "oniguruma.h") still compile.
onig_install = os.path.join(self.build_folder, "oniguruma")
copy(self, "*.a", src=os.path.join(onig_install, "lib"),
dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, "*.lib", src=os.path.join(onig_install, "lib"),
dst=os.path.join(self.package_folder, "lib"), keep_path=False)
copy(self, "*.h", src=os.path.join(onig_install, "include"),
dst=os.path.join(self.package_folder, "include"), keep_path=False)

def package_info(self):
self.cpp_info.libs = ["tml"]
# tml depends on onig at link time; list both so consumers get all symbols resolved.
# Order matters for static linking: tml first (it references onig), then onig.
self.cpp_info.libs = ["tml", "onig"]
self.cpp_info.set_property("cmake_file_name", "TextMateLib")
self.cpp_info.set_property("cmake_target_name", "TextMateLib::tml")

Expand Down
7 changes: 7 additions & 0 deletions packages/tml-cpp/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.14)
project(PackageTest CXX)

find_package(TextMateLib REQUIRED CONFIG)

add_executable(example src/example.cpp)
target_link_libraries(example PRIVATE TextMateLib::tml)
25 changes: 25 additions & 0 deletions packages/tml-cpp/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import os
from conan import ConanFile
from conan.tools.cmake import CMake, cmake_layout
from conan.tools.build import can_run


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

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

def layout(self):
cmake_layout(self)

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

def test(self):
if can_run(self):
cmd = os.path.join(self.cpp.build.bindir, "example")
self.run(cmd, env="conanrun")
18 changes: 18 additions & 0 deletions packages/tml-cpp/test_package/src/example.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "tml/c_api.h"

int main() {
TextMateOnigLib lib = textmate_oniglib_create();
if (!lib) {
return 1;
}

TextMateRegistry registry = textmate_registry_create(lib);
if (!registry) {
textmate_oniglib_dispose(lib);
return 1;
}

textmate_registry_dispose(registry);
textmate_oniglib_dispose(lib);
return 0;
}
Loading