Skip to content
Open
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
9 changes: 7 additions & 2 deletions examples/quickstart-cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
cmake_minimum_required(VERSION 3.16)
# Allow CMake 4.x to configure dependencies built with older cmake_minimum_required
set(CMAKE_POLICY_VERSION_MINIMUM 3.5)
project(SimpleCppFlowerClient VERSION 0.10
DESCRIPTION "Creates a Simple C++ Flower client that trains a linear model on synthetic data."
LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
option(USE_LOCAL_FLWR "Use local Flower directory instead of fetching from GitHub" OFF)

######################
### Download gRPC
### Download gRPC

include(FetchContent)
FetchContent_Declare(
Expand Down Expand Up @@ -58,16 +60,19 @@ target_link_libraries(flwr
${_REFLECTION}
${_GRPC_GRPCPP}
${_PROTOBUF_LIBPROTOBUF}
ssl
crypto
)

target_include_directories(flwr PUBLIC
${FLWR_INCLUDE_DIR}
${grpc_SOURCE_DIR}/third_party/boringssl-with-bazel/src/include
Comment thread
uncleDecart marked this conversation as resolved.
)

######################
### FLWR_CLIENT
file(GLOB FLWR_CLIENT_SRCS src/*.cc)
set(EXECUTABLE_NAME flwr_client)
set(EXECUTABLE_NAME flower-supernode)
add_executable(${EXECUTABLE_NAME} ${FLWR_CLIENT_SRCS})

target_include_directories(${EXECUTABLE_NAME} PUBLIC
Expand Down
42 changes: 42 additions & 0 deletions examples/quickstart-cpp/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
FROM ubuntu:22.04

ARG DEBIAN_FRONTEND=noninteractive

# Install system dependencies
RUN apt-get update && apt-get install -y \
build-essential \
cmake \
git \
curl \
wget \
autoconf \
libtool \
pkg-config \
python3 \
python-is-python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*

# Install Flower and Python dependencies for the server
RUN pip3 install --no-cache-dir \
flwr \
numpy \
hatchling

WORKDIR /app

# Copy proto definitions and C++ SDK source
COPY framework/proto /app/framework/proto
COPY framework/cc /app/framework/cc

# Copy the quickstart-cpp example
COPY examples/quickstart-cpp /app/examples/quickstart-cpp

# Build the C++ client (this fetches gRPC ~v1.43.2 and generates protos)
WORKDIR /app/examples/quickstart-cpp
RUN cmake -S . -B build -DUSE_LOCAL_FLWR=ON \
-DCMAKE_BUILD_TYPE=Release \
-DFETCHCONTENT_QUIET=OFF \
&& cmake --build build -j$(nproc)

WORKDIR /app/examples/quickstart-cpp
39 changes: 27 additions & 12 deletions examples/quickstart-cpp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ dataset: [Synthetic]
framework: [C++]
---

# Flower Clients in C++ (under development)

> [!WARNING]\
> This example is compatible with `flwr<1.13.0`. We are currently updating it to the newer `flwr run` way of running Flower Apps.
# Flower Clients in C++

In this example you will train a linear model on synthetic data using C++ clients.

Expand All @@ -19,31 +16,49 @@ Many thanks to the original contributors to this code:
- Francisco José Solís (code re-organization)
- Andreea Zaharia (training algorithm and data generation)

## Install requirements
## Option 1: Run with Docker (recommended)

You'll need CMake and Python with `flwr` installed.
The easiest way to test the C++ client is with Docker Compose, which builds the
client and runs the full federated learning setup automatically.

### Building the example
```bash
cd examples/quickstart-cpp
docker compose up --build
```

This example provides you with a `CMakeLists.txt` file to configure and build the client. Feel free to take a look inside it to see what is happening under the hood.
This starts the SuperLink, two C++ SuperNode clients, and the Python ServerApp.

To clean up:

```bash
docker compose down
```

## Option 2: Run locally

### Install requirements

You'll need CMake, a C++17 compiler, and Python with `flwr` and `numpy` installed.

### Building the example

```bash
cmake -S . -B build
cmake -S . -B build -DUSE_LOCAL_FLWR=ON
cmake --build build
```

## Run the `Flower SuperLink`, the two clients, and the `Flower ServerApp` in separate terminals
### Run the SuperLink, two clients, and the ServerApp in separate terminals

```bash
flwr-superlink --insecure
```

```bash
build/flwr_client 0 127.0.0.1:9092
build/flower-supernode 0 127.0.0.1:9092
```

```bash
build/flwr_client 1 127.0.0.1:9092
build/flower-supernode 1 127.0.0.1:9092
```

```bash
Expand Down
22 changes: 22 additions & 0 deletions examples/quickstart-cpp/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
"""Placeholder ClientApp for C++ quickstart.

The actual clients are C++ SuperNodes that connect via gRPC.
This file satisfies the Flower app configuration requirement.
"""
import flwr as fl


def client_fn(context) -> fl.client.Client:
"""Placeholder client factory for the C++ quickstart.

The actual clients for this example are implemented in C++ and connect to
the server via gRPC. This Python client placeholder exists only to satisfy
the Flower app configuration requirements and must not be started.
"""
raise RuntimeError(
"This Python ClientApp is a placeholder for the C++ quickstart. "
"Use the C++ SuperNode clients instead of starting this client."
)


app = fl.client.ClientApp(client_fn=client_fn)
75 changes: 75 additions & 0 deletions examples/quickstart-cpp/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
services:
# Builds the C++ client binary and Python server dependencies
cpp-build:
build:
context: ../..
dockerfile: examples/quickstart-cpp/Dockerfile
image: flower-quickstart-cpp

# Flower SuperLink (manages FL lifecycle, runs ServerApp as subprocess)
superlink:
image: flower-quickstart-cpp
depends_on:
cpp-build:
condition: service_completed_successfully
command: flower-superlink --insecure
ports:
- "9091:9091"
- "9092:9092"
- "9093:9093"
working_dir: /app/examples/quickstart-cpp
networks:
- flwr-network

# C++ SuperNode client 0
client-0:
image: flower-quickstart-cpp
depends_on:
superlink:
condition: service_started
command: >
bash -c "sleep 4 && ./build/flower-supernode 0 superlink:9092"
working_dir: /app/examples/quickstart-cpp
networks:
- flwr-network

# C++ SuperNode client 1
client-1:
image: flower-quickstart-cpp
depends_on:
superlink:
condition: service_started
command: >
bash -c "sleep 8 && ./build/flower-supernode 1 superlink:9092"
working_dir: /app/examples/quickstart-cpp
networks:
- flwr-network

# Submit the ServerApp run to the SuperLink
runner:
image: flower-quickstart-cpp
depends_on:
superlink:
condition: service_started
client-0:
condition: service_started
client-1:
condition: service_started
command:
- bash
- -c
- |
mkdir -p /root/.flwr
cat > /root/.flwr/config.toml << 'EOF'
[superlink.local-deployment]
address = "superlink:9093"
insecure = true
EOF
sleep 12 && flwr run . local-deployment
working_dir: /app/examples/quickstart-cpp
networks:
- flwr-network

networks:
flwr-network:
driver: bridge
28 changes: 28 additions & 0 deletions examples/quickstart-cpp/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "quickstart-cpp"
version = "1.0.0"
description = "Quickstart C++ with Flower"
license = "Apache-2.0"
requires-python = ">=3.9"
dependencies = [
"flwr>=1.27.0",
"numpy>=1.26.0",
]

[tool.hatch.build.targets.wheel]
packages = ["."]

[tool.flwr.app]
publisher = "flwrlabs"

[tool.flwr.app.components]
serverapp = "server:app"
clientapp = "client:app"

[tool.flwr.app.config]
num-server-rounds = 3

2 changes: 1 addition & 1 deletion examples/quickstart-cpp/src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ int main(int argc, char **argv) {
if (argc != 3) {
std::cout << "Client takes 2 mandatory arguments as follows: " << std::endl;
std::cout << "./client CLIENT_ID SERVER_URL" << std::endl;
std::cout << "Example: ./flwr_client 0 '127.0.0.1:8080'" << std::endl;
std::cout << "Example: ./flower-supernode 0 '127.0.0.1:9092'" << std::endl;
return 0;
}

Expand Down
16 changes: 11 additions & 5 deletions framework/cc/flwr/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
cmake_minimum_required(VERSION 3.16)
# Allow CMake 4.x to configure dependencies built with older cmake_minimum_required
set(CMAKE_POLICY_VERSION_MINIMUM 3.5)
project(flwr VERSION 1.0
DESCRIPTION "Flower Library that packages gRPC and other dependencies"
LANGUAGES CXX)
Expand Down Expand Up @@ -71,10 +73,13 @@ endmacro()
# Using the above macro for all proto files
GENERATE_AND_COPY(transport)
GENERATE_AND_COPY(node)
GENERATE_AND_COPY(task)
GENERATE_AND_COPY(fleet)
GENERATE_AND_COPY(error)
GENERATE_AND_COPY(recordset)
GENERATE_AND_COPY(recorddict)
GENERATE_AND_COPY(message)
GENERATE_AND_COPY(heartbeat)
GENERATE_AND_COPY(run)
GENERATE_AND_COPY(fab)
GENERATE_AND_COPY(fleet)

add_library(flwr_grpc_proto STATIC ${ALL_PROTO_FILES})

Expand All @@ -97,7 +102,8 @@ add_library(flwr ${FLWR_SRCS})

target_include_directories(flwr PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<BUILD_INTERFACE:${grpc_SOURCE_DIR}/third_party/boringssl-with-bazel/src/include>
Comment thread
uncleDecart marked this conversation as resolved.
)

# Link gRPC and other dependencies
target_link_libraries(flwr PRIVATE flwr_grpc_proto)
# Link gRPC and other dependencies (ssl/crypto from BoringSSL for node auth)
target_link_libraries(flwr PRIVATE flwr_grpc_proto ssl crypto)
Loading
Loading