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

CMake build script updates #140

Merged
merged 26 commits into from
Aug 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
083bb0c
Remove IDE project files + add to .gitignore
madebr Aug 3, 2020
486c1a7
Add .editorconfig file to automatically apply styles
madebr Aug 3, 2020
82b3854
Add build directories to .gitignore
madebr Aug 3, 2020
8d994a1
Use FindPythonInterp to look for python + create nicer embedded source
madebr Aug 3, 2020
682db24
Add SEASOCKS_SHARED and SEASOCKS_STATIC option + allow non-PIC static…
madebr Aug 3, 2020
aae4195
Generate internal/Config.h file with @ONLY
madebr Aug 3, 2020
a3704c5
Reformat cmake scripts
madebr Aug 3, 2020
008d195
Export cmake targets in SeasocksTargets.cmake + generate SeasocksConf…
madebr Aug 3, 2020
abcf1da
Remove double quotes from add_subdirectory arguments
madebr Aug 3, 2020
57302ab
Install license
madebr Aug 3, 2020
8511eb4
Add conanfile build script
madebr Aug 3, 2020
0ba88d0
Fix conanfile.py for use on Windows
madebr Aug 3, 2020
f49f674
Fix compile options for MSVC
madebr Aug 3, 2020
40524c1
Object library also needs to include directories
madebr Aug 3, 2020
9b1397f
Fix embedded source generator for Python3
madebr Aug 3, 2020
ae8c75a
Only add ZLIB's include directories to object library when deflate is…
madebr Aug 3, 2020
0f5aeb3
fPIC does not exist on Windows
madebr Aug 3, 2020
7e6a8b3
Fix license of conanfile
madebr Aug 3, 2020
797f4a8
Fail with a fatal error when building on Windows
madebr Aug 3, 2020
29a0119
Revert "Remove IDE project files + add to .gitignore"
madebr Aug 3, 2020
5336cfa
Fix bad grammar in error message
madebr Aug 3, 2020
8706615
Tests and exemples were linked to static libraries by default
madebr Aug 3, 2020
42db87d
Create all executables in 2 forms: linked to static seasocks and link…
madebr Aug 3, 2020
7db5c37
Need to link to the object library instead of the executable
madebr Aug 4, 2020
81a0093
Shared libraries need the --coverage linker flag too
madebr Aug 4, 2020
01bc83a
Run test target instead of custom unittest target
madebr Aug 4, 2020
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
8 changes: 8 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
root = true

[*]
indent_style = space
trim_trailing_whitespace = true
insert_final_newline = true
indent_size = 4
tab_width = 4
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
build*
*.swp
*~
.gdb_history
Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ before_script:

script:
- cd build
- cmake --build . --target unittest
- cmake --build . --target test
- ctest -D ExperimentalBuild -j${JOBS}
- ctest -D ExperimentalMemCheck -j${JOBS}
- bash <(curl -s https://codecov.io/bash)
36 changes: 25 additions & 11 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
cmake_minimum_required(VERSION 3.3)

set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

project(Seasocks VERSION 1.4.3)

if(WIN32)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe Mac OS should be included too? Test for not-linux?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Indeed, test should include APPLE

message(FATAL_ERROR "${PROJECT_NAME} does not support Windows")
Copy link
Owner

Choose a reason for hiding this comment

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

Thanks!

endif()

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

option(SEASOCKS_SHARED "Build shared Seasocks library" ON)
option(SEASOCKS_STATIC "Build static Seasocks library" ON)
option(UNITTESTS "Build unittests." ON)
option(COVERAGE "Build with code coverage enabled" OFF)
option(SEASOCKS_EXAMPLE_APP "Build the example applications." ON)
option(DEFLATE_SUPPORT "Include support for deflate (requires zlib)." ON)

if (NOT SEASOCKS_SHARED AND NOT SEASOCKS_STATIC)
message(FATAL_ERROR "SEASOCKS_SHARED and SEASOCKS_STATIC cannot both be false.")
endif ()

if (DEFLATE_SUPPORT)
set(DEFLATE_SUPPORT_BOOL "true")
else ()
Expand All @@ -29,39 +37,45 @@ set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.h.in internal/Config.h)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/Config.h.in internal/Config.h @ONLY)
add_compile_options(-Wall -Werror -Wextra -pedantic -pedantic-errors)
if (COVERAGE)
add_compile_options(--coverage -O0)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
set(CMAKE_SHARED_LINKER_FLAGS "${SHARED_EXE_LINKER_FLAGS} --coverage")
endif ()

find_package(Threads)
find_package(PythonInterp)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nice, didn't know that package! 👍

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's superseded by FindPython3, but that's not available on older cmake releases.



find_program(PYTHON_BIN NAMES python python3 DOC "Python executable")

if (NOT PYTHON_BIN)
if (NOT PYTHONINTERP_FOUND)
message(SEND_ERROR "Python not found")
else()
message(STATUS "Using Python: '${PYTHON_BIN}'")
message(STATUS "Using Python: '${PYTHON_EXECUTABLE}'")
endif ()

if (DEFLATE_SUPPORT)
find_package(ZLIB REQUIRED)
endif ()

add_subdirectory("src")
add_subdirectory(src)
Copy link
Owner

Choose a reason for hiding this comment

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

much nicer, thank you


include(CMakePackageConfigHelpers)
configure_package_config_file(cmake/SeasocksConfig.cmake.in ${PROJECT_NAME}Config.cmake
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}/"
)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)

install(FILES
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}/
)
install(FILES
LICENSE
DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/licenses/${PROJECT_NAME}"
)
2 changes: 1 addition & 1 deletion cmake/Config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace seasocks {

struct Config {
static constexpr auto version = "@PROJECT_VERSION@";
static constexpr bool deflateEnabled = ${DEFLATE_SUPPORT_BOOL};
static constexpr bool deflateEnabled = @DEFLATE_SUPPORT_BOOL@;
mattgodbolt marked this conversation as resolved.
Show resolved Hide resolved
};

}
Expand Down
14 changes: 14 additions & 0 deletions cmake/SeasocksConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
set(SEASOCKS_SHARED @SEASOCKS_SHARED@)
set(SEASOCKS_STATIC @SEASOCKS_STATIC@)
set(SEASOCKS_DEFLATE_SUPPORT @DEFLATE_SUPPORT@)

if(SEASOCKS_STATIC)
find_package(Threads REQUIRED)
if(SEASOCKS_DEFLATE_SUPPORT)
find_package(ZLIB REQUIRED)
endif()
endif()

include("${CMAKE_CURRENT_LIST_DIR}/SeasocksTargets.cmake")

@PACKAGE_INIT@
mattgodbolt marked this conversation as resolved.
Show resolved Hide resolved
82 changes: 82 additions & 0 deletions conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
from conans import CMake, ConanFile, tools
Copy link
Owner

Choose a reason for hiding this comment

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

I'm happy to have this here, but forgive my ignorance: how might this work to get seasocks in conan build center?

Also it looks like we're missing a test_package -- have you been able to test that this seasocks build works?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This won't help at all for getting seasocks in cci, because it doesn't follow cci practices.
Also, in my own experience, using a conanfile makes it easier to test on ci.
If you ever lose your mind and want to add support for Windows, then you can use it to build on appveyor.
A simple conan install.. && conan build .. & conan test .. should work™ .

In theory, now you can add a job on travis that uses this conanfile.
The test() method can be used to run the unit tests.
I haven't added a test_package, because the intention of this recipe is not to package seasocks, but to allow it to build (and test).

Copy link
Owner

Choose a reason for hiding this comment

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

I see. I can't see that we'd ever use conan to build seasocks in this case (it has so few upstream dependencies). My projects that do have upstream deps do use conan, but I don't want to rely on it here. However, that doesn't mean this isn't super useful!

We will definitely add a conan test job once this is working, how would you suggest doing so with your changes here?

conan install.. && conan build .. & conan test ..

Aside: I do so hate the multi-stage aspect of conan. In all my experience, if there are manual steps, then people will forget them! In my own projects I always use the conan.cmake file to make conan part of the build itself...I've spent too long debugging things like "oh, you forgot to conan install:? You're probably building against the old libraries...argh!")

Copy link
Collaborator Author

@madebr madebr Aug 3, 2020

Choose a reason for hiding this comment

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

This requires adding new jobs, that will run the conan commands.
I would add a CONAN_INSTALL_ARGS environment variable to .travis.yml.

Aside: I do so hate the multi-stage aspect of conan. In all my experience, if there are manual steps, then people will forget them! In my own projects I always use the conan.cmake file to make conan part of the build itself...I've spent too long debugging things like "oh, you forgot to conan install:? You're probably building against the old libraries...argh!")

It's a matter of taste I guess.
I always try to make my project package manager agnostic.
This allows me to build with the libraries of a linux package manager.

(Matt accidentally edited this comment; I hope I've un-edited back appropriate)

Copy link
Owner

Choose a reason for hiding this comment

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

Oops! I meant to reply!!! Not edit your comment 😊

I tried to say:

This requires adding new jobs, that will run the conan commands.
I would add a CONAN_INSTALL_ARGS environment variable to .travis.yml.

I get that, just quickly, how might one actually build seasocks using conan? conan install .. && conan build .. && conan test .. like you mentioned above? Would that actually run the tests? Thanks again for teaching me this.

I always try to make my project package manager agnostic.
Got it: that makes sense. In my world having the one way that just works and is reproducible is most important, but I have the luxury of mostly getting to choose this within my team etc

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I get that, just quickly, how might one actually build seasocks using conan? conan install .. && conan build .. && conan test .. like you mentioned above? Would that actually run the tests? Thanks again for teaching me this.

I was wrong there. The intended use of conan test is only to test conan packages.
What can be done is use the virtualenv generator. The tests can then be run from any script (bash/python/ctest/...). The virtualenv makes sure that paths of all dependencies are in the search path (LD_LIBRARY_PATH/PATH/DYLD_LIBRARY_PATH/...). This is especially required for shared library dependencies.

I always try to make my project package manager agnostic.
Got it: that makes sense. In my world having the one way that just works and is reproducible is most important, but I have the luxury of mostly getting to choose this within my team etc

Check the conanfile.py of thie recipe. It writes a wrapper CMakeLists.txt in the build directory that includes the source directory. It is more or less the inverse approach as your conan.cmake. (conan.cmake's driver is cmake. In this pr, the driver is conan)

Copy link
Owner

Choose a reason for hiding this comment

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

I'll try and work through that once we're merged in. I'm not quite following but I imagine trying to do it will elucidate more than reading dry documentation.

from conans.errors import ConanException, ConanInvalidConfiguration
import os
import re
import shutil
import textwrap


class SeasocksConan(ConanFile):
name = "seasocks"
def set_version(self):
cmakelists = tools.load(os.path.join(self.recipe_folder, "CMakeLists.txt"))
try:
m = next(re.finditer(r"project\(Seasocks VERSION ([0-9.]+)\)", cmakelists))
except StopIteration:
raise ConanException("Cannot detect Seasocks version from CMakeLists.txt")
self.version = m.group(1)
topics = ("seasocks", "embeddable", "webserver", "websockets")
homepage = "https://github.com/mattgodbolt/seasocks"
url = "https://github.com/mattgodbolt/seasocks"
license = "BSD-2-Clause"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"static": [True, False],
"fPIC": [True, False],
mattgodbolt marked this conversation as resolved.
Show resolved Hide resolved
"with_zlib": [True, False],
}
default_options = {
"shared": True,
"static": True,
"fPIC": True,
"with_zlib": True,
}
no_copy_source = True
generators = "cmake", "cmake_find_package"

def export_sources(self):
shutil.copytree("cmake", os.path.join(self.export_sources_folder, "cmake"))
shutil.copytree("scripts", os.path.join(self.export_sources_folder, "scripts"))
shutil.copytree("src", os.path.join(self.export_sources_folder, "src"))
shutil.copy("CMakeLists.txt", self.export_sources_folder)
shutil.copy("LICENSE", self.export_sources_folder)

def config_options(self):
if self.settings.os == "Windows":
del self.options.fPIC

def configure(self):
if not self.options.static:
del self.options.fPIC
if not any((self.options.shared, self.options.static)):
raise ConanInvalidConfiguration("Need to build a shared and/or static library")

def requirements(self):
if self.options.with_zlib:
self.requires("zlib/1.2.11")

def build(self):
if self.source_folder == self.build_folder:
raise ConanException("Cannot build in same folder as sources")
tools.save(os.path.join(self.build_folder, "CMakeLists.txt"), textwrap.dedent("""\
cmake_minimum_required(VERSION 3.0)
project(cmake_wrapper)

include("{install_folder}/conanbuildinfo.cmake")
conan_basic_setup(TARGETS)

add_subdirectory("{source_folder}" seasocks)
""").format(
source_folder=self.source_folder.replace("\\", "/"),
install_folder=self.install_folder.replace("\\", "/")))
cmake = CMake(self)
cmake.definitions["SEASOCKS_SHARED"] = self.options.shared
cmake.definitions["SEASOCKS_STATIC"] = self.options.static
cmake.definitions["DEFLATE_SUPPORT"] = self.options.with_zlib
cmake.configure(source_folder=self.build_folder)
cmake.build()

def package(self):
cmake = CMake(self)
cmake.install()
10 changes: 5 additions & 5 deletions scripts/gen_embedded.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
}\n
"""

MAX_SLICE = 70

MAX_SLICE = 16

def as_byte(data):
if sys.version_info < (3,):
Expand All @@ -45,11 +44,12 @@ def parse_arguments():

def create_file_byte(name, file_bytes):
output = []
output.append(' const char %s[] = {' % name)
output.append(' const char %s[%d] = {\n' % (name, len(file_bytes) + 1))

for start in range(0, len(file_bytes), MAX_SLICE):
output.append('' + "".join(["'\\x%02x'," % as_byte(x) for x in file_bytes[start:start+MAX_SLICE]]) + "\n")
output.append('0};\n')
output.append(" " + "".join("'\\x{:02x}',".format(as_byte(x)) for x in file_bytes[start:start+MAX_SLICE]) + "\n")
output.append(' 0x00,\n')
output.append(' };\n')
return ''.join(output)


Expand Down
26 changes: 21 additions & 5 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@

add_subdirectory("main/c")
add_subdirectory("main/web")
add_subdirectory(main/c)
add_subdirectory(main/web)

macro(add_seasocks_executable _name)
add_library(${_name}_objs OBJECT ${ARGN})
target_link_libraries(${_name}_objs PRIVATE seasocks_headers)
if (TARGET seasocks)
Copy link
Owner

Choose a reason for hiding this comment

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

Neat way of doing this!

add_executable(${_name} $<TARGET_OBJECTS:${_name}_objs>)
target_link_libraries(${_name} PRIVATE seasocks)
endif ()
if (TARGET seasocks_so)
add_executable(${_name}_so $<TARGET_OBJECTS:${_name}_objs>)
target_link_libraries(${_name}_so PRIVATE seasocks_so)
endif ()
endmacro()

macro(seasocks_link_libraries _name)
target_link_libraries(${_name}_objs ${ARGN})
endmacro()

if (SEASOCKS_EXAMPLE_APP)
add_subdirectory("app/c")
add_subdirectory(app/c)
endif ()

if (UNITTESTS)
find_program(CMAKE_MEMORYCHECK_COMMAND valgrind)
enable_testing()
add_subdirectory("test/c")
add_subdirectory(test/c)
endif ()

32 changes: 19 additions & 13 deletions src/app/c/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
macro(add_app _NAME)
add_executable(${_NAME} ${_NAME}.cpp)
target_link_libraries(${_NAME} seasocks "${ZLIB_LIBRARIES}")
macro(add_app NAME)
add_seasocks_executable(${NAME} ${NAME}.cpp)
endmacro()

add_app(ph_test)
Expand All @@ -12,14 +11,21 @@ add_app(ws_test_poll)
add_app(async_test)
add_app(streaming_test)

add_custom_command(TARGET ws_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${PROJECT_SOURCE_DIR}/src/ws_test_web $<TARGET_FILE_DIR:ws_test>/src/ws_test_web)
function(copy_directory_post_build TARGET SUBDIRECTORY)
set(name)
if (TARGET ${TARGET})
set(name ${TARGET})
elseif(TARGET ${TARGET}_so)
set(name ${TARGET}_so)
endif()
if (name)
add_custom_command(TARGET ${name} POST_BUILD
COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${PROJECT_SOURCE_DIR}/${SUBDIRECTORY}" "$<TARGET_FILE_DIR:${name}>/${SUBDIRECTORY}"
)
endif ()
endfunction()

add_custom_command(TARGET async_test POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${PROJECT_SOURCE_DIR}/src/async_test_web $<TARGET_FILE_DIR:async_test>/src/async_test_web)

add_custom_command(TARGET ws_chatroom POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${PROJECT_SOURCE_DIR}/src/ws_chatroom_web $<TARGET_FILE_DIR:ws_chatroom>/src/ws_chatroom_web)
copy_directory_post_build(ws_test src/ws_test_web)
copy_directory_post_build(async_test src/async_test_web)
copy_directory_post_build(ws_chatroom src/ws_chatroom_web)
Loading