libwebsockets icon indicating copy to clipboard operation
libwebsockets copied to clipboard

Integrate libwebsockets into existing projects (based on CMake build method)

Open Alvazz opened this issue 2 years ago • 1 comments

Hi lws-team, First of all thank you for sharing such great work.

My project is built based on cmake. It mainly runs on windows and macos platforms. I hope to integrate libwebsockets into the project through cmake in an elegant way. I hope to get help from lws-team.

I have read almost all the files in the READMEs directory. This may be the most attentive and serious work I have ever seen on any project. So much documentation, so awesome. It's a pity that there are no tips on how to integrate it into the cmake project :(

emm...since I don't understand libwebsockets, I thought of the simplest way, which is to show the cmake structure of my project so that lws-team can better guide me on how to integrate libwebsockets elegantly.

TL;DR

My project folder structure is roughly as follows:

my-app
   --cmake(this folder stores some .cmake files, such as Findjansson.cmake, or FindMbedTLS.cmake)
   --deps
       --w32-pthread
           CMakeLists.txt(in the w32-pthread directory)
       --jansson
       CMakeLists.txt(in the deps root directory)
   --libcore
   --libcat-win
   --libwasliy-win
   --plugins
   --UI
   CMakeLists.txt(in the my-app root directory)

I usually put third-party dependencies in the deps directory This CMakeLists.txt is located in the root directory of my-app, and its content is as follows:

cmake_minimum_required(VERSION 3.16...3.25)

if(MYAPP_CMAKE_VERSION VERSION_GREATER_EQUAL 3.0.0)
  include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/common/bootstrap.cmake")

  project(my-app VERSION ${MYAPP_VERSION_CANONICAL})

  if(CMAKE_SIZEOF_VOID_P EQUAL 4)
    include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/32bit/projects.cmake")
    return()
  endif()


  option(ENABLE_RELEASE_BUILD "Enable all options for a release build" OFF)

  add_subdirectory(libcore)
  if(OS_WINDOWS)
    add_subdirectory(libcat-win)
    add_subdirectory(libwasliy-win)
  endif()
  add_subdirectory(plugins)
  add_subdirectory(UI)

  message_configuration()
  return()
endif()

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/Modules")
include(VersionConfig)

# Prohibit in-source builds
if("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
  message(FATAL_ERROR "MYAPP: You cannot build in a source directory (or any directory with CMakeLists.txt file)."
                      "Please make a build subdirectory. Feel free to remove CMakeCache.txt and CMakeFiles.")
endif()

project(my-app VERSION ${MYAPP_VERSION_CANONICAL})
set_property(GLOBAL PROPERTY USE_FOLDERS ON)

# Use target folders for MSVC/Xcode/etc.
include(DeprecationHelpers)
# Set default compiler flags
include(CompilerConfig)

# Allow selection of common build types via UI
if(NOT CMAKE_BUILD_TYPE)
  set(CMAKE_BUILD_TYPE
      "RelWithDebInfo"
      CACHE STRING "MYAPP build type [Release, RelWithDebInfo, Debug, MinSizeRel]" FORCE)
  set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS Release RelWithDebInfo Debug MinSizeRel)
endif()

# Global project options
option(BUILD_FOR_DISTRIBUTION "Build for distribution (enables optimizations)" OFF)
option(USE_LIBCXX "Use libc++ instead of libstdc++" ${APPLE})
option(BUILD_TESTS "Build test directory (includes test sources and possibly a platform test executable)" OFF)

if(OS_WINDOWS)
  option(INSTALLER_RUN
         "Build a multiarch installer (needs to run independently after both archs have compiled) (Windows)" OFF)
endif()

setup_myapp_project()
mark_as_advanced(BUILD_TESTS USE_LIBCXX)

if(INSTALLER_RUN)
  generate_multiarch_installer()
  return()
endif()

# MYAPP deps
add_subdirectory(deps)

# Tests
if(ENABLE_UNIT_TESTS)
  enable_testing()
endif()

if(BUILD_TESTS OR ENABLE_UNIT_TESTS)
  add_subdirectory(test)
endif()

Next is the content of the CMakeLists.txt file located in the deps root directory:

if(MYAPP_CMAKE_VERSION VERSION_GREATER_EQUAL 3.0.0)
  return()
endif()

if(OS_WINDOWS)
  if(NOT MINGW)
    add_subdirectory(w32-pthreads)
  endif()
endif()

# Use bundled jansson version as fallback
find_package(Jansson 2.5 QUIET)
if(NOT TARGET Jansson::Jansson)
  myapp_status(STATUS "Jansson >=2.5 not found, building bundled version.")

  add_subdirectory(jansson)
  add_library(Jansson::Jansson ALIAS jansson)
else()
  myapp_status(STATUS "Using system Jansson library.")
endif()

The CMakeLists.txt in the win32-pthreads directory looks like this:

cmake_minimum_required(VERSION 3.24...3.25)

legacy_check()

add_library(w32-pthreads SHARED EXCLUDE_FROM_ALL )
add_library(MYAPP::w32-pthreads ALIAS w32-pthreads)

target_sources(w32-pthreads PRIVATE implement.h pthread.c pthread.h sched.h semaphore.h w32-pthreads.rc)
target_compile_definitions(w32-pthreads PRIVATE __CLEANUP_C PTW32_BUILD)
target_include_directories(w32-pthreads PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>")

configure_file(cmake/windows/my-app.rc.in w32-pthreads.rc)

set_target_properties_myapp(w32-pthreads PROPERTIES FOLDER deps)

set_property(
  TARGET w32-pthreads
  APPEND
  PROPERTY PUBLIC_HEADER pthread.h sched.h)
target_export(w32-pthreads)

The above content and directory structure constitute the cmake function of my project. If I want to integrate libwebsockets into my project, how should I do it? Looking forward to your guidance.

Thanks, Best Wishes!

Alvazz avatar Sep 11 '23 20:09 Alvazz

There's lots of ways to add LWS into a cmake file.

  • Build as a submodule, link statically
  • Link dynamically with an OS installed release
  • Link dynamically and have the library in the path of your executable so it is found before the OS's library
  • Cross compiling
  • Lots of other use cases

IMO your best bet is to break your cmake into a test case, and then try to port what you learned to your project's CMakeLists.txt. I am just a fan of minimal test cases when troubleshooting, though. It's usually the fastest way to figure things out.

I did so here https://github.com/dylanetaft/lws_cmake_testcase

For an example of build as a submodule, link statically You can pull LWS into your project path as a git submodule https://chrisjean.com/git-submodules-adding-using-removing-and-updating/ Same thing you're doing with add_subdirectory in your existing CMakeLists.txt file

LWS's cmake files expose a handful of library targets and include targets, see the CMakeLists.txt in what I put on github there.

pkg_config also works if your environment has it, but that's for like OS installed libraries usually. ..... find_package(PkgConfig) pkg_check_modules(LIB_WEBSOCKETS REQUIRED libwebsockets) ...... target_link_libraries( yourapp ${LIB_WEBSOCKETS_LIBRARIES} ) target_include_directories( yourapp PUBLIC ${LIB_WEBSOCKETS_DIRS} )

target_compile_options( test PUBLIC ${LIB_WEBSOCKETS_CFLAGS_OTHER} )

Distros can have fairly out of date packages for LWS. Linking statically is sort of a safe bet and should provide for a reliable build process. Or having the dynamic library in the binary path. The MIT license is pretty permissive I think but I am not a lawyer.

I posted a similar question earlier, was closed as it is indeed more of a cmake question...butttt cmake doesn't dictate what you export as the cmake library name with add_library...or any helper things for linking, include paths, or cflags needed.

I ended up going to chatgpt and asked it generically, if I have a library B as a submodule in a git repo for project a, how do I link my application a to library b - and it informed me I needed to set stuff in the CMakeLists.txt file in library B with examples. It let me know what to look for at least, that I can't actually do it without knowing what B is making available as there isn't a standard.
Google sends you on a bad path with StackOverflow examples where AI is way more tailored with answers. Really good for learning stuff...usually.

I am using msys2 for compiling, no idea about Visual Studio, I'm guessing VS is super smart about cmake and importing third party libraries into a project though!

dylanetaft avatar Oct 16 '23 06:10 dylanetaft