소스 검색

Merge pull request #716 from uilianries/feature/conan-ci

Build Conan package in CI (#712 )
bel2125 6 년 전
부모
커밋
c5cf339fc9
11개의 변경된 파일449개의 추가작업 그리고 78개의 파일을 삭제
  1. 2 0
      .gitignore
  2. 67 2
      .travis.yml
  3. 6 1
      CMakeLists.txt
  4. 57 36
      appveyor.yml
  5. 82 0
      conan/build.py
  6. 11 0
      conan/test_package/CMakeLists.txt
  7. 19 0
      conan/test_package/conanfile.py
  8. 102 0
      conan/test_package/test_package.cpp
  9. 14 0
      conan/travis/build.sh
  10. 22 0
      conan/travis/install.sh
  11. 67 39
      conanfile.py

+ 2 - 0
.gitignore

@@ -267,3 +267,5 @@ requests.db
 ci/lua
 
 
+# Conan test cache
+conan/test_package/build

+ 67 - 2
.travis.yml

@@ -42,7 +42,7 @@ install:
 before_script:
   # Add an IPv6 config - see the corresponding Travis issue
   # https://github.com/travis-ci/travis-ci/issues/8361
-  - if [ "${ENABLE_IPV6}" == "YES" -a "${TRAVIS_OS_NAME}" == "linux" ]; then 
+  - if [ "${ENABLE_IPV6}" == "YES" -a "${TRAVIS_OS_NAME}" == "linux" ]; then
       echo "Activating IPv6 on Travis";
       sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6';
     fi
@@ -119,6 +119,40 @@ after_success:
       bash <(curl -s https://codecov.io/bash);
     fi
 
+conan-linux: &conan-linux
+    os: linux
+    dist: xenial
+    language: python
+    python: "3.7"
+    services:
+      - docker
+    if: tag IS present
+    before_install:
+      - true
+    install:
+      - ./conan/travis/install.sh
+    before_script:
+      - true
+    script:
+      - ./conan/travis/build.sh
+    after_success:
+      - true
+
+conan-osx: &conan-osx
+    os: osx
+    language: generic
+    if: tag IS present
+    before_install:
+      - true
+    install:
+      - ./conan/travis/install.sh
+    before_script:
+      - true
+    script:
+      - ./conan/travis/build.sh
+    after_success:
+      - true
+
 
 ##############################################################################
 # build matrix
@@ -304,7 +338,7 @@ matrix:
       ENABLE_DUKTAPE=NO
       NO_CACHING=YES
       ALLOW_WARNINGS=YES
-  
+
   - os: linux
     sudo: required
     compiler: gcc
@@ -676,6 +710,37 @@ matrix:
       NO_CACHING=YES
       ALLOW_WARNINGS=YES
 
+  - <<: *conan-linux
+    env: CONAN_GCC_VERSIONS=4.9 CONAN_DOCKER_IMAGE=conanio/gcc49 CONAN_DOCKER_32_IMAGES=1
+  - <<: *conan-linux
+    env: CONAN_GCC_VERSIONS=5 CONAN_DOCKER_IMAGE=conanio/gcc5 CONAN_DOCKER_32_IMAGES=1
+  - <<: *conan-linux
+    env: CONAN_GCC_VERSIONS=6 CONAN_DOCKER_IMAGE=conanio/gcc6 CONAN_DOCKER_32_IMAGES=1
+  - <<: *conan-linux
+    env: CONAN_GCC_VERSIONS=7 CONAN_DOCKER_IMAGE=conanio/gcc7 CONAN_DOCKER_32_IMAGES=1
+  - <<: *conan-linux
+    env: CONAN_GCC_VERSIONS=8 CONAN_DOCKER_IMAGE=conanio/gcc8 CONAN_DOCKER_32_IMAGES=1
+  - <<: *conan-linux
+    env: CONAN_CLANG_VERSIONS=3.9 CONAN_DOCKER_IMAGE=conanio/clang39 CONAN_DOCKER_32_IMAGES=1
+  - <<: *conan-linux
+    env: CONAN_CLANG_VERSIONS=4.0 CONAN_DOCKER_IMAGE=conanio/clang40 CONAN_DOCKER_32_IMAGES=1
+  - <<: *conan-linux
+    env: CONAN_CLANG_VERSIONS=5.0 CONAN_DOCKER_IMAGE=conanio/clang50 CONAN_DOCKER_32_IMAGES=1
+  - <<: *conan-linux
+    env: CONAN_CLANG_VERSIONS=6.0 CONAN_DOCKER_IMAGE=conanio/clang60 CONAN_DOCKER_32_IMAGES=1
+  - <<: *conan-osx
+    osx_image: xcode8.3
+    env: CONAN_APPLE_CLANG_VERSIONS=8.1
+  - <<: *conan-osx
+    osx_image: xcode9
+    env: CONAN_APPLE_CLANG_VERSIONS=9.0
+  - <<: *conan-osx
+    osx_image: xcode9.4
+    env: CONAN_APPLE_CLANG_VERSIONS=9.1
+  - <<: *conan-osx
+    osx_image: xcode10.1
+    env: CONAN_APPLE_CLANG_VERSIONS=10.0
+
 # Remove Lua build, until someone knows how to fix the CMake files
 #
 #  - dist: trusty

+ 6 - 1
CMakeLists.txt

@@ -384,7 +384,12 @@ if (CIVETWEB_ENABLE_CXX)
   add_cxx_compiler_flag(-pedantic-errors)
   add_cxx_compiler_flag(-fvisibility=hidden)
   add_cxx_compiler_flag(-fstack-protector-strong RELEASE)
-  add_cxx_compiler_flag(-flto RELEASE)
+
+  if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR
+      "${BUILD_SHARED_LIBS}" STREQUAL "SHARED" OR
+      ${CMAKE_CXX_COMPILER_VERSION} GREATER 5)
+    add_cxx_compiler_flag(-flto RELEASE)
+  endif()
   if (${CIVETWEB_ENABLE_ASAN})
   add_cxx_compiler_flag(-fsanitize=undefined DEBUG)
   add_cxx_compiler_flag(-fsanitize=address DEBUG)

+ 57 - 36
appveyor.yml

@@ -6,14 +6,13 @@ build:
 
 
 skip_commits:
-  # Builds just testing something on Travis CI don't need to be 
+  # Builds just testing something on Travis CI don't need to be
   # done on AppVeyor
   message: /\[Travis\]/
   # Dont build, if only documentation was changed
   files:
   - '**/*.md'
 
-
 environment:
   enable_cxx: NO
   enable_ssl_dynamic_loading: YES
@@ -268,40 +267,16 @@ environment:
       configuration: Release
       platform: x64
       image: Ubuntu1804
-
-matrix:
-  fast_finish: false
-  allow_failures:
-    # Experimental Ubuntu
-    - id: Ubuntu1604-GCC-x64
-      compiler: gcc-5.1.0-posix
-      build_shared: NO
-      no_files: NO
-      enable_ipv6: YES
-      enable_ssl: YES
-      enable_websockets: YES
-      no_cgi: NO
-      no_caching: NO
-      enable_stats: YES
-      configuration: Release
-      platform: x64
-      image: Ubuntu1604
-    - id: Ubuntu1804-GCC-x64
-      compiler: gcc-5.1.0-posix
-      build_shared: NO
-      no_files: NO
-      enable_ipv6: YES
-      enable_ssl: YES
-      enable_websockets: YES
-      no_cgi: NO
-      no_caching: NO
-      enable_stats: YES
-      configuration: Release
-      platform: x64
-      image: Ubuntu1804
-
-
-
+    # Conan builds
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      CONAN_VISUAL_VERSIONS: 12
+      PYTHON: "C:\\Python37"
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+      CONAN_VISUAL_VERSIONS: 14
+      PYTHON: "C:\\Python37"
+    - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+      CONAN_VISUAL_VERSIONS: 15
+      PYTHON: "C:\\Python37"
 
 install:
   # Derive some extra information
@@ -474,3 +449,49 @@ cache:
 artifacts:
   - path: dist\*
 
+for:
+  -
+    matrix:
+      only:
+        - configuration: Release
+      fast_finish: false
+      allow_failures:
+        # Experimental Ubuntu
+        - id: Ubuntu1604-GCC-x64
+          compiler: gcc-5.1.0-posix
+          build_shared: NO
+          no_files: NO
+          enable_ipv6: YES
+          enable_ssl: YES
+          enable_websockets: YES
+          no_cgi: NO
+          no_caching: NO
+          enable_stats: YES
+          configuration: Release
+          platform: x64
+          image: Ubuntu1604
+        - id: Ubuntu1804-GCC-x64
+          compiler: gcc-5.1.0-posix
+          build_shared: NO
+          no_files: NO
+          enable_ipv6: YES
+          enable_ssl: YES
+          enable_websockets: YES
+          no_cgi: NO
+          no_caching: NO
+          enable_stats: YES
+          configuration: Release
+          platform: x64
+          image: Ubuntu1804
+
+  -
+    matrix:
+      only:
+        - PYTHON: "C:\\Python37"
+    skip_non_tags: true
+    install:
+      - set PATH=%PATH%;%PYTHON%/Scripts/
+      - pip.exe install conan conan_package_tools
+    build: false
+    test_script:
+      - python conan/build.py

+ 82 - 0
conan/build.py

@@ -0,0 +1,82 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import re
+from cpt.packager import ConanMultiPackager
+from cpt.ci_manager import CIManager
+from cpt.printer import Printer
+
+
+class BuilderSettings(object):
+
+    @property
+    def branch(self):
+        """ Get branch name
+        """
+        printer = Printer(None)
+        ci_manager = CIManager(printer)
+        return ci_manager.get_branch()
+
+    @property
+    def username(self):
+        """ Set civetweb as package's owner
+        """
+        return os.getenv("CONAN_USERNAME", "civetweb")
+
+    @property
+    def upload(self):
+        """ Set civetweb repository to be used on upload.
+            The upload server address could be customized by env var
+            CONAN_UPLOAD. If not defined, the method will check the branch name.
+            Only master or CONAN_STABLE_BRANCH_PATTERN will be accepted.
+            The master branch will be pushed to testing channel, because it does
+            not match the stable pattern. Otherwise it will upload to stable
+            channel.
+        """
+        if os.getenv("CONAN_UPLOAD", None) is not None:
+            return os.getenv("CONAN_UPLOAD")
+
+        prog = re.compile(self.stable_branch_pattern)
+        if self.branch and prog.match(self.branch):
+            return "https://api.bintray.com/conan/civetweb/conan"
+
+        return None
+
+    @property
+    def upload_only_when_stable(self):
+        """ Force to upload when match stable pattern branch
+        """
+        return os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", True)
+
+    @property
+    def stable_branch_pattern(self):
+        """ Only upload the package the branch name is like a tag
+        """
+        return os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v(\d+\.\d+)")
+
+    @property
+    def version(self):
+        regex = re.compile(self.stable_branch_pattern)
+        match = regex.match(self.branch)
+        if match:
+            return match.group(1)
+        return "latest"
+
+    @property
+    def reference(self):
+        """ Read project version from branch name to create Conan referece
+        """
+        return os.getenv("CONAN_REFERENCE", "civetweb/{}".format(self.version))
+
+if __name__ == "__main__":
+    settings = BuilderSettings()
+    builder = ConanMultiPackager(
+        reference=settings.reference,
+        username=settings.username,
+        upload=settings.upload,
+        upload_only_when_stable=settings.upload_only_when_stable,
+        stable_branch_pattern=settings.stable_branch_pattern,
+        test_folder=os.path.join("conan", "test_package"))
+    builder.add_common_builds(pure_c=False)
+    builder.run()

+ 11 - 0
conan/test_package/CMakeLists.txt

@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 2.8.11)
+project(test_package CXX)
+
+set(CMAKE_VERBOSE_MAKEFILE ON)
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup()
+
+add_executable(${PROJECT_NAME} test_package.cpp)
+target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS})
+set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 11)

+ 19 - 0
conan/test_package/conanfile.py

@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+import os
+from conans import ConanFile, CMake
+
+
+class TestPackageConan(ConanFile):
+    settings = "os", "compiler", "build_type", "arch"
+    generators = "cmake"
+
+    def build(self):
+        cmake = CMake(self)
+        cmake.configure()
+        cmake.build()
+
+    def test(self):
+        assert os.path.isfile(os.path.join(self.deps_cpp_info["civetweb"].rootpath, "licenses", "LICENSE.md"))
+        bin_path = os.path.join("bin", "test_package")
+        self.run(bin_path, run_environment=True)

+ 102 - 0
conan/test_package/test_package.cpp

@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018 the CivetWeb developers
+ * MIT License
+ */
+
+/* Simple demo of a REST callback. */
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "civetweb.h"
+
+#define PORT "8080"
+#define HOST_INFO "http://localhost:8080"
+#define EXAMPLE_URI "/example"
+
+static int exitNow = 0;
+
+static int
+ExampleGET(struct mg_connection* conn)
+{
+    mg_send_http_ok(conn, "text/plain", 10);
+    exitNow = 1;
+	return 200;
+}
+
+static int
+ExampleHandler(struct mg_connection *conn, void *cbdata)
+{
+	const struct mg_request_info *ri = mg_get_request_info(conn);
+	(void)cbdata; /* currently unused */
+
+	if (0 == strcmp(ri->request_method, "GET")) {
+		return ExampleGET(conn);
+	}
+	return 405;
+}
+
+int
+log_message(const struct mg_connection *conn, const char *message)
+{
+	puts(message);
+	return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+	struct mg_callbacks callbacks;
+	struct mg_context *ctx;
+	time_t start_t;
+	time_t end_t;
+	double diff_t;
+	int err = 0;
+
+	mg_init_library(0);
+
+	/* Callback will print error messages to console */
+	memset(&callbacks, 0, sizeof(callbacks));
+	callbacks.log_message = log_message;
+
+	/* Start CivetWeb web server */
+	ctx = mg_start(&callbacks, 0, NULL);
+
+	/* Check return value: */
+	if (ctx == NULL) {
+		fprintf(stderr, "Cannot start CivetWeb - mg_start failed.\n");
+		return EXIT_FAILURE;
+	}
+
+	/* Add handler EXAMPLE_URI, to explain the example */
+	mg_set_request_handler(ctx, EXAMPLE_URI, ExampleHandler, 0);
+
+	/* Show sone info */
+	printf("Start example: %s%s\n", HOST_INFO, EXAMPLE_URI);
+
+
+	/* Wait until the server should be closed */
+	time(&start_t);
+	while (!exitNow) {
+#ifdef _WIN32
+		Sleep(1000);
+#else
+		sleep(1);
+#endif
+        time(&end_t);
+		diff_t = difftime(end_t, start_t);
+		if (diff_t > 3.0) {
+			break;
+		}
+	}
+
+	/* Stop the server */
+	mg_stop(ctx);
+	return EXIT_SUCCESS;
+}

+ 14 - 0
conan/travis/build.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+set -e
+set -x
+
+if [[ "$(uname -s)" == 'Darwin' ]]; then
+    if which pyenv > /dev/null; then
+        eval "$(pyenv init -)"
+    fi
+    pyenv activate conan
+fi
+
+conan user
+python conan/build.py

+ 22 - 0
conan/travis/install.sh

@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -ex
+
+if [[ "$(uname -s)" == 'Darwin' ]]; then
+    brew update || brew update
+    brew outdated pyenv || brew upgrade pyenv
+    brew install pyenv-virtualenv
+    brew install cmake || true
+
+    if which pyenv > /dev/null; then
+        eval "$(pyenv init -)"
+    fi
+
+    pyenv install 3.7.1
+    pyenv virtualenv 3.7.1 conan
+    pyenv rehash
+    pyenv activate conan
+fi
+
+pip install conan==1.10.2
+pip install conan_package_tools

+ 67 - 39
conanfile.py

@@ -1,61 +1,89 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*
 from conans import ConanFile, tools, CMake
-import os
+
 
 class civetwebConan(ConanFile):
     name = "civetweb"
-    version = "1.10"
     license = "MIT"
     url = "https://github.com/civetweb/civetweb"
     description = "Embedded C/C++ web server"
-    settings = "os", "compiler", "build_type", "arch"
-    exports_sources = "*"
-    requires = "OpenSSL/1.0.2@conan/stable"
+    author = "Bernhard Lehner <bel2125@gmail.com>"
+    topics = ("conan", "civetweb", "web-server", "embedded")
+    exports = ("LICENSE.md", "README.md")
+    exports_sources = ("src/*", "cmake/*", "include/*", "CMakeLists.txt")
     generators = "cmake"
+    settings = "os", "compiler", "build_type", "arch"
     options = {
         "shared"            : [True, False],
+        "fPIC"              : [True, False],
         "enable_ssl"        : [True, False],
         "enable_websockets" : [True, False],
+        "enable_ipv6"       : [True, False],
         "enable_cxx"        : [True, False]
     }
-    default_options = (
-        "shared=False",
-        "enable_ssl=True",
-        "enable_websockets=True",
-        "enable_cxx=True",
-    )
-
-    def optionBool(self, b):
-        if b:
-            return "ON"
-        else:
-            return "OFF"
-
-    def parseOptionsToCMake(self):
-        cmakeOpts = {
-            "CIVETWEB_BUILD_TESTING" : "OFF",
-            "CIVETWEB_ENABLE_LUA" : "OFF",
-            "CIVETWEB_ENABLE_SERVER_EXECUTABLE" : "OFF",
-            "CIVETWEB_INSTALL_EXECUTABLE" : "OFF",
-            "CIVETWEB_ENABLE_ASAN" : "OFF"
-        }
-
-        cmakeOpts["BUILD_SHARED_LIBS"] = self.optionBool(self.options.shared)
-        cmakeOpts["CIVETWEB_ENABLE_SSL"] = self.optionBool(self.options.enable_ssl)
-        cmakeOpts["CIVETWEB_ENABLE_WEBSOCKETS"] = self.optionBool(self.options.enable_websockets)
-        cmakeOpts["CIVETWEB_ENABLE_CXX"] = self.optionBool(self.options.enable_cxx)
-
-        return cmakeOpts
+    default_options = {
+        "shared"            : False,
+        "fPIC"              : True,
+        "enable_ssl"        : True,
+        "enable_websockets" : True,
+        "enable_ipv6"       : True,
+        "enable_cxx"        : True
+    }
 
-    def build(self):
+    def config_options(self):
+        if self.settings.os == 'Windows':
+            del self.options.fPIC
+
+    def configure(self):
+        if not self.options.enable_cxx:
+            del self.settings.compiler.libcxx
+
+    def requirements(self):
+        if self.options.enable_ssl:
+            self.requires("OpenSSL/1.0.2q@conan/stable")
+
+    def _configure_cmake(self):
         cmake = CMake(self)
-        os.makedirs("./buildit")
-        cmake.configure(defs=self.parseOptionsToCMake(), build_dir="./buildit")
+        cmake.verbose = True
+        cmake.definitions["CIVETWEB_ENABLE_SSL"] = self.options.enable_ssl
+        cmake.definitions["CIVETWEB_ENABLE_WEBSOCKETS"] = self.options.enable_websockets
+        cmake.definitions["CIVETWEB_ENABLE_IPV6"] = self.options.enable_ipv6
+        cmake.definitions["CIVETWEB_ENABLE_CXX"] = self.options.enable_cxx
+        cmake.definitions["CIVETWEB_BUILD_TESTING"] = False
+        cmake.definitions["CIVETWEB_ENABLE_ASAN"] = False
+        cmake.configure(build_dir="build_subfolder")
+        return cmake
+
+    def build(self):
+        tools.replace_in_file(file_path="CMakeLists.txt",
+                              search="project (civetweb)",
+                              replace="""project (civetweb)
+                                 include(conanbuildinfo.cmake)
+                                 conan_basic_setup()""")
+        cmake = self._configure_cmake()
         cmake.build()
-        cmake.install()
 
     def package(self):
-        # nothing to do here now
-        pass
+        self.copy("LICENSE.md", dst="licenses")
+        cmake = self._configure_cmake()
+        cmake.install()
 
     def package_info(self):
         self.cpp_info.libs = tools.collect_libs(self)
+        if self.settings.os == "Linux":
+            self.cpp_info.libs.extend(["dl", "rt", "pthread"])
+            if self.options.enable_cxx:
+                self.cpp_info.libs.append("m")
+        elif self.settings.os == "Macos":
+            self.cpp_info.exelinkflags.append("-framework Cocoa")
+            self.cpp_info.sharedlinkflags = self.cpp_info.exelinkflags
+            self.cpp_info.defines.append("USE_COCOA")
+        elif self.settings.os == "Windows":
+            self.cpp_info.libs.append("Ws2_32")
+        if self.options.enable_websockets:
+            self.cpp_info.defines.append("USE_WEBSOCKET")
+        if self.options.enable_ipv6:
+            self.cpp_info.defines.append("USE_IPV6")
+        if not self.options.enable_ssl:
+            self.cpp_info.defines.append("NO_SSL")