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/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,27 @@ jobs:

- name: Run API tests
run: npm run test:api

test-conan:
name: Conan Package Test
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

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

- name: Test Conan package
run: conan create . --build=missing
54 changes: 54 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -273,3 +273,57 @@ jobs:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

publish-conan:
name: Publish to Conan
needs: [build-matrix, create-release]
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
strategy:
matrix:
include:
- os: Linux
arch: x86_64
- os: Linux
arch: armv8
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'

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

- name: Extract version from tag
id: version
run: |
TAG="${{ github.ref_name }}"
VERSION=${TAG#v}
echo "version=$VERSION" >> $GITHUB_OUTPUT

- name: Create Conan package
run: |
conan create . --build=missing

- name: Upload Conan package artifact
uses: actions/upload-artifact@v4
with:
name: conan-package-${{ matrix.os }}-${{ matrix.arch }}
path: ~/.conan2/p/

# Publish to a custom Conan remote (requires CONAN_REMOTE_URL and CONAN_API_KEY secrets)
- name: Publish to Conan remote
if: ${{ vars.CONAN_REMOTE_URL != '' }}
env:
CONAN_REMOTE_URL: ${{ vars.CONAN_REMOTE_URL }}
CONAN_API_KEY: ${{ secrets.CONAN_API_KEY }}
run: |
conan remote add publish "$CONAN_REMOTE_URL"
conan remote login publish -p "$CONAN_API_KEY" ci
conan upload "ipv6-parse/${{ steps.version.outputs.version }}" -r publish --confirm
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,7 @@ install_manifest.txt

# pkg-config generated file (but not .pc.in templates)
ipv6-parse.pc

# Conan
CMakeUserPresets.json
test_package/build/
10 changes: 9 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,16 @@ set_property(GLOBAL PROPERTY USE_FOLDERS ON)

file(GLOB ipv6_sources "ipv6.h" "ipv6.c" ${IPV6_CONFIG_HEADER_PATH}/ipv6_config.h)

option(IPV6_CONAN_BUILD "Building with Conan package manager" OFF)

if (MSVC)
set(ipv6_target_compile_flags "/MTd /Wall /WX /wd5045 /ZI /Od /D_NO_CRT_STDIO_INLINE=1")
if (IPV6_CONAN_BUILD)
# When building with Conan, use minimal flags and let Conan control runtime
# Disable C4711 (auto inline) and C5045 (Spectre) warnings
set(ipv6_target_compile_flags "/W4 /wd4711 /wd5045")
else ()
set(ipv6_target_compile_flags "/MTd /Wall /WX /wd5045 /ZI /Od /D_NO_CRT_STDIO_INLINE=1")
endif ()
else ()
set(ipv6_target_compile_flags "-Wall -Werror -Wno-long-long -pedantic -std=c99 -Wno-unused-but-set-variable")
if (ENABLE_COVERAGE)
Expand Down
137 changes: 137 additions & 0 deletions README_CONAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Conan Package for ipv6-parse

This document describes how to use the ipv6-parse library with [Conan](https://conan.io/), the C/C++ package manager.

## Quick Start

### Installing from Local Source

```bash
# Build and install to local cache
conan create . --build=missing

# Or export without building
conan export .
```

### Using in Your Project

Add ipv6-parse to your `conanfile.txt`:

```ini
[requires]
ipv6-parse/1.2.1

[generators]
CMakeDeps
CMakeToolchain
```

Or in your `conanfile.py`:

```python
from conan import ConanFile

class MyProjectConan(ConanFile):
requires = "ipv6-parse/1.2.1"
generators = "CMakeDeps", "CMakeToolchain"
```

### CMake Integration

In your `CMakeLists.txt`:

```cmake
cmake_minimum_required(VERSION 3.12)
project(myproject C)

find_package(ipv6-parse REQUIRED)

add_executable(myapp main.c)
target_link_libraries(myapp ipv6-parse::ipv6-parse)
```

### Building Your Project

```bash
# Install dependencies
conan install . --output-folder=build --build=missing

# Configure with CMake
cmake -B build -DCMAKE_TOOLCHAIN_FILE=build/conan_toolchain.cmake

# Build
cmake --build build
```

## Package Options

| Option | Default | Description |
|----------|---------|-----------------------------------|
| `shared` | `False` | Build shared library |
| `fPIC` | `True` | Generate position-independent code |

### Example: Building Shared Library

```bash
conan create . -o ipv6-parse/*:shared=True --build=missing
```

## Example Usage

```c
#include <stdio.h>
#include <string.h>
#include <ipv6.h>

int main(void) {
ipv6_address_full_t addr;
const char *input = "2001:db8::1";

if (ipv6_from_str(input, strlen(input), &addr)) {
char buffer[IPV6_STRING_SIZE];
ipv6_to_str(&addr, buffer, sizeof(buffer));
printf("Parsed: %s\n", buffer);
}
return 0;
}
```

## Development

### Running Tests

The package includes a test consumer in `test_package/` that verifies the package works correctly:

```bash
conan create . --build=missing
```

### Supported Platforms

- Linux (GCC, Clang)
- macOS (Apple Clang)
- Windows (MSVC)

### Conan 2.x Compatibility

This package is designed for Conan 2.x and uses the modern Conan API.

## CI/CD Integration

The Conan package is automatically tested and published via GitHub Actions:

- **CI Testing**: Every push and PR runs `conan create` on Linux, macOS, and Windows
- **Release Publishing**: Tagged releases (e.g., `v1.2.1`) trigger automatic Conan package creation

### Publishing to a Custom Remote

To publish releases to your own Conan remote, configure these GitHub repository settings:

1. **Variables** (Settings > Secrets and variables > Actions > Variables):
- `CONAN_REMOTE_URL`: Your Conan remote URL (e.g., `https://your-artifactory.com/artifactory/api/conan/conan-local`)

2. **Secrets** (Settings > Secrets and variables > Actions > Secrets):
- `CONAN_API_KEY`: API key or token for authentication

The publish step will be skipped if `CONAN_REMOTE_URL` is not configured.
31 changes: 11 additions & 20 deletions conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,17 @@ class Ipv6ParseConan(ConanFile):
"cmake/*",
"ipv6.c",
"ipv6.h",
"ipv6_wasm.c",
"cmdline.c",
"LICENSE",
"README.md",
"ipv6_config.h.in",
"ipv6-parse.pc.in",
"cmake/ipv6-parse-config.cmake.in",
"LICENSE",
"README.md", # Required by CPack in CMakeLists.txt
)

def set_version(self):
"""Extract version from CMakeLists.txt"""
content = load(self, os.path.join(self.recipe_folder, "CMakeLists.txt"))
version_match = re.search(r"project\(ipv6-parse VERSION ([0-9.]+)", content)
# CMakeLists.txt uses project(ipv6 VERSION x.y.z)
version_match = re.search(r"project\(ipv6 VERSION \"?([0-9.]+)\"?", content)
if version_match:
self.version = version_match.group(1)
else:
Expand All @@ -69,6 +68,8 @@ def generate(self):
tc.variables["BUILD_SHARED_LIBS"] = self.options.shared
tc.variables["ENABLE_COVERAGE"] = False
tc.variables["PARSE_TRACE"] = False
# Let Conan control MSVC runtime settings
tc.variables["IPV6_CONAN_BUILD"] = True
tc.generate()

def build(self):
Expand All @@ -77,29 +78,19 @@ def build(self):
cmake.build()

def package(self):
cmake = CMake(self)
cmake.install()

# Copy license
copy(self, "LICENSE",
src=self.source_folder,
dst=os.path.join(self.package_folder, "licenses"))

# Copy documentation
copy(self, "README*.md",
src=self.source_folder,
dst=os.path.join(self.package_folder, "docs"))
cmake = CMake(self)
cmake.install()

def package_info(self):
self.cpp_info.libs = ["ipv6-parse"]
self.cpp_info.includedirs = ["include"]

# Set component for pkg-config
# Set properties for pkg-config
self.cpp_info.set_property("pkg_config_name", "ipv6-parse")

# Set component for CMake
# Set properties for CMake find_package
self.cpp_info.set_property("cmake_file_name", "ipv6-parse")
self.cpp_info.set_property("cmake_target_name", "ipv6-parse::ipv6-parse")

# Add bin folder to PATH for CLI tool
self.cpp_info.bindirs = ["bin"]
7 changes: 7 additions & 0 deletions test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.12)
project(test_ipv6_parse C)

find_package(ipv6-parse REQUIRED)

add_executable(test_ipv6_parse test_ipv6_parse.c)
target_link_libraries(test_ipv6_parse ipv6-parse::ipv6-parse)
25 changes: 25 additions & 0 deletions 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 Ipv6ParseTestConan(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, "test_ipv6_parse")
self.run(cmd, env="conanrun")
18 changes: 18 additions & 0 deletions test_package/test_ipv6_parse.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include <stdio.h>
#include <string.h>
#include <ipv6.h>

int main(void) {
ipv6_address_full_t addr;
const char *test_addr = "2001:db8::1";

if (ipv6_from_str(test_addr, strlen(test_addr), &addr)) {
char buffer[IPV6_STRING_SIZE];
ipv6_to_str(&addr, buffer, sizeof(buffer));
printf("Successfully parsed IPv6 address: %s\n", buffer);
return 0;
}

printf("Failed to parse IPv6 address\n");
return 1;
}