emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.72k stars 3.3k forks source link

find_package not works in emcmake #13310

Open lwyj123 opened 3 years ago

lwyj123 commented 3 years ago

I am using Cmake for build large project and want to migrate to WebAssembly and the project have some dependencies. When I build the project using my CMakeLists.txt, I just got some errors of find_package

-- Could NOT find PIXMAN, try to set the path to PIXMAN root folder in the system variable PIXMAN (missing: PIXMAN_LIBRARIES PIXMAN_INCLUDE_DIRS) 
-- Could NOT find ZLIB (missing: ZLIB_LIBRARY ZLIB_INCLUDE_DIR) 
CMake Error at /usr/local/Cellar/cmake/3.19.2/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:218 (message):
  Could NOT find PNG (missing: PNG_LIBRARY PNG_PNG_INCLUDE_DIR)
Call Stack (most recent call first):
  /usr/local/Cellar/cmake/3.19.2/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:582 (_FPHSA_FAILURE_MESSAGE)
  /usr/local/Cellar/cmake/3.19.2/share/cmake/Modules/FindPNG.cmake:156 (find_package_handle_standard_args)
  external/cairo/CMakeLists.txt:7 (find_package)

Here is the cairo CMakeLists.txt

project(cairo)
cmake_minimum_required(VERSION 2.9)

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

find_package(Pixman REQUIRED)
find_package(PNG REQUIRED)
find_package(ZLIB REQUIRED)
find_package(Freetype)
find_package(Threads)
find_package(Fontconfig)

include(Configure_config.cmake)
include(Configure_features.cmake)
include_directories(${CMAKE_BINARY_DIR})

if(CAIRO_HAS_PTHREAD)
    list(APPEND CAIRO_LIBS -lpthread)
endif()

if (WIN32)
    set(CAIRO_LIBS gdi32 msimg32 user32 winmm)
endif()

include_directories(${PIXMAN_INCLUDE_DIR} ${PNG_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
list(APPEND CAIRO_LIBS  ${PIXMAN_LIBRARY} ${PNG_LIBRARY} ${ZLIB_LIBRARY})

if(FONTCONFIG_FOUND)
    list(APPEND CAIRO_LIBS ${FONTCONFIG_LIBRARY})
endif()

if(FREETYPE_FOUND)
    find_package(BZip2)
    include_directories(${FREETYPE_INCLUDE_DIRS})
    include_directories(${BZIP2_INCLUDE_DIR})
    list(APPEND CAIRO_LIBS ${FREETYPE_LIBRARIES} ${BZIP2_LIBRARIES})
endif()

include_directories(src)
add_subdirectory(src)

cmake_policy (SET CMP0072 NEW)

And some cmake file like FindPixman is

# - Try to find PIXMAN
# Once done this will define
#
#  PIXMAN_ROOT_DIR - Set this variable to the root installation of PIXMAN
#  PIXMAN_FOUND - system has PIXMAN
#  PIXMAN_INCLUDE_DIRS - the PIXMAN include directory
#  PIXMAN_LIBRARIES - Link these to use PIXMAN
#
#  Copyright (c) 2008 Joshua L. Blocher <verbalshadow at gmail dot com>
#  Copyright (c) 2011 Ralf Habacker, <ralf dot habacker at freenet dot de>
#  Copyright (c) 2012 Dmitry Baryshnikov <polimax at mail dot ru>
#  Copyright (c) 2015 Mikhail Paulyshka <pavlyshko-m at yandex dot by>
#
# Distributed under the OSI-approved BSD License
#
if (NOT WIN32)
    find_package(PkgConfig)
    if (PKG_CONFIG_FOUND)
        pkg_check_modules(_PIXMAN pixman)
        SET(PIXMAN_VERSION ${_PIXMAN_VERSION})
    endif (PKG_CONFIG_FOUND)
endif (NOT WIN32)

SET(_PIXMAN_ROOT_HINTS
    $ENV{PIXMAN}
    ${CMAKE_FIND_ROOT_PATH}
    ${PIXMAN_ROOT_DIR}
) 

SET(_PIXMAN_ROOT_PATHS
    $ENV{PIXMAN}/src
    /usr
    /usr/local
)

SET(_PIXMAN_ROOT_HINTS_AND_PATHS
    HINTS ${_PIXMAN_ROOT_HINTS}
    PATHS ${_PIXMAN_ROOT_PATHS}
)

FIND_PATH(PIXMAN_INCLUDE_DIR
    NAMES
        "pixman.h"
    HINTS
        ${_PIXMAN_INCLUDEDIR}
        ${_PIXMAN_ROOT_HINTS_AND_PATHS}
    PATH_SUFFIXES
        include
        "include/pixman-1"
)  

FIND_LIBRARY(PIXMAN_LIBRARY
    NAMES
        pixman-1 
        pixman-1d
        pixman-1_static
        pixman-1_staticd 
    HINTS
        ${_PIXMAN_LIBDIR}
        ${_PIXMAN_ROOT_HINTS_AND_PATHS}
    PATH_SUFFIXES
        "lib"
        "local/lib"
) 

SET(PIXMAN_LIBRARIES 
    ${PIXMAN_LIBRARY}
)

SET(PIXMAN_INCLUDE_DIRS
    ${PIXMAN_INCLUDE_DIR}
)

if (NOT PIXMAN_VERSION)
    if (EXISTS "${PIXMAN_INCLUDE_DIRS}/pixman-version.h")
        file(READ "${PIXMAN_INCLUDE_DIRS}/pixman-version.h" PIXMAN_VERSION_CONTENT)

        string(REGEX MATCH "#define +PIXMAN_VERSION_MAJOR +([0-9]+)" _dummy "${PIXMAN_VERSION_CONTENT}")
        set(PIXMAN_VERSION_MAJOR "${CMAKE_MATCH_1}")

        string(REGEX MATCH "#define +PIXMAN_VERSION_MINOR +([0-9]+)" _dummy "${PIXMAN_VERSION_CONTENT}")
        set(PIXMAN_VERSION_MINOR "${CMAKE_MATCH_1}")

        string(REGEX MATCH "#define +PIXMAN_VERSION_MICRO +([0-9]+)" _dummy "${PIXMAN_VERSION_CONTENT}")
        set(PIXMAN_VERSION_MICRO "${CMAKE_MATCH_1}")

        set(PIXMAN_VERSION "${PIXMAN_VERSION_MAJOR}.${PIXMAN_VERSION_MINOR}.${PIXMAN_VERSION_MICRO}")
    endif (EXISTS "${PIXMAN_INCLUDE_DIRS}/pixman-version.h")
endif(NOT PIXMAN_VERSION)

include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PIXMAN
    REQUIRED_VARS PIXMAN_LIBRARIES PIXMAN_INCLUDE_DIRS
    VERSION_VAR PIXMAN_VERSION
    FAIL_MESSAGE "Could NOT find PIXMAN, try to set the path to PIXMAN root folder in the system variable PIXMAN"
)

MARK_AS_ADVANCED(PIXMAN_CONFIG_INCLUDE_DIR PIXMAN_INCLUDE_DIR PIXMAN_INCLUDE_DIRS PIXMAN_LIBRARY PIXMAN_LIBRARIES)

But It works when I just used cmake to build.

What's the solution for that?

phcerdan commented 3 years ago

I am hitting this (I am just touching waters with emscripten). In my case with find_package(Boost).

CMake Error at /PATH/build-dependencies-clang/boost-build/lib/cmake/Boost-1.72.0/BoostConfig.cmake:120 (find_package):
  Could not find a package configuration file provided by "boost_headers"
  (requested version 1.72.0) with any of the following names:

    boost_headersConfig.cmake
    boost_headers-config.cmake

  Add the installation prefix of "boost_headers" to CMAKE_PREFIX_PATH or set
  "boost_headers_DIR" to a directory containing one of the above files.  If
  "boost_headers" provides a separate development package or SDK, be sure it
  has been installed.
Call Stack (most recent call first):
  PATH/build-dependencies-clang/boost-build/lib/cmake/Boost-1.72.0/BoostConfig.cmake:158 (boost_find_component)
  /usr/share/cmake-3.19/Modules/FindBoost.cmake:460 (find_package)
  CMakeLists.txt:70 (find_package)

cmake --version: 3.19.5 emscripten --version: 2.0.13-1

Same command without emcmake works as @lwyj123 reported. Any hint?

stale[bot] commented 2 years ago

This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 30 days. Feel free to re-open at any time if this issue is still relevant.

Sakari369 commented 2 years ago

I was also getting this issue when trying to use find_library to find some custom libraries I had built for webassembly. Probably this is caused by these lines in the Emscripten CMakeToolchain:

# Since Emscripten is a cross-compiler, we should never look at the
# system-provided directories like /usr/include and so on. Therefore only
# CMAKE_FIND_ROOT_PATH should be used as a find directory. See
# http://www.cmake.org/cmake/help/v3.0/variable/CMAKE_FIND_ROOT_PATH_MODE_INCLUDE.html
if (NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY)
  set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
endif()
if (NOT CMAKE_FIND_ROOT_PATH_MODE_INCLUDE)
  set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()
if (NOT CMAKE_FIND_ROOT_PATH_MODE_PACKAGE)
  set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
endif()

Essentially what these do is forcing only Emscripting find_library (and assuming find_package also) to look inside the Emscripten directories.

At least find_library started working in my project when commenting off the

set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)

Part.

This can be misleading for maintaining your own CMake projects, probably it should be mentioned somewhere in the Emscripten documentation that by default the toolchain restricts library directories only to the Emscripten sysroot directories.

You can add

-DCMAKE_FIND_DEBUG_MODE=ON

To your Cmake generation commandline to see where Cmake is trying to find the packages.

sbc100 commented 2 years ago

Where are you expecting cmake to look in your case? I.e. where are you install these packages? Are we talking about /usr/lib and /usr/include? Or somewhere else?

wernight commented 1 year ago

@sbc100 Yes, I installed them on a Ubuntu-based system using apt.

sbc100 commented 1 year ago

Emscripten cannot use the libraries packaged for ubuntu because its a different architecture.

And libraries of packages you want to use with emscripten would need to be compiled yourself. You would then need to either install those packages into the emscripten sysroot or somehow point cmake at the location where you built them.

Ozaq commented 11 months ago

I am running into the same issue in our case however we use find package to use header only libraries that are installed in a custom location / are part of the source tree but are third party.

TheMadman commented 3 months ago

Hello,

In my case, I was using find_library to find a library I have built with emscripten and installed to a custom, separate prefix, e.g. ~/devel/emsdk-prefix/{lib,include,etc.}.

When I'm using a prefix like this without emsdk, I will set up environment variables like PATH, LIBRARY_PATH, CPATH etc., to make them visible to the build system so the extra libraries can be linked against.

Is there an intended way to manage this kind of thing in emsdk? Just move the archive.a files into the build directory or such?

sbc100 commented 3 months ago

I think there are probably 3 common patterns:

  1. Install you packaged into emscripten's sysroot (e.g. emsdk/cache/sysroot/{lib,share,include})
  2. Install you package into some other custom location and set library paths and include paths accrordingly
  3. Don't even install the package and just link to directly when you build it (e.g. -I/path/to/mylib/include -L/path/to/mylib/lib -lmylib)

If you do (1) then I think find_package will just work because the emscripten cmake setup is aware of the sysroot.

If you do (2) then i think you would need to teach cmake/find_package about your install location. I think there are various ways to configure to the paths that find_package looks in.

If you do (3) then you wouldn't be using find_package at all.

TheMadman commented 3 months ago

Perfect, I'll have a closer look at configuring the CMake search paths for the find_* functions. Tainting the sysroot sounds fragile, but at least it's an option if I can't find something better. Thanks!

On Donnerstag, 11. Juli 2024 00:08:58 MESZ Sam Clegg wrote:

I think there are probably 3 common patterns:

  1. Install you packaged into emscripten's sysroot (e.g. emsdk/cache/sysroot/{lib,share,include}) 2. Install you package into some other custom location and set library paths and include paths accrordingly
  2. Don't even install the package and just link to directly when you build it (e.g. -I/path/to/mylib/include -L/path/to/mylib/lib -lmylib)

If you do (1) then I think find_package will just work because the emscripten cmake setup is aware of the sysroot.

If you do (2) then i think you would need to teach cmake/find_package about your install location. I think there are various ways to configure to the paths that find_package looks in.

If you do (3) then you wouldn't be using find_package at all.

TheMadman commented 3 months ago

Alright, I was able to find a solution I'm happy with.

The emscripten cmake toolchain file sets:

if (NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY)
  set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
endif()

which means the CMAKE_FIND_ROOT_PATH is the only set of paths searched. However, the toolchain file appends to that variable, so setting it on the command line to an install prefix makes searches work again:

emcmake cmake -DCMAKE_INSTALL_PREFIX="/path/to/prefix" -DCMAKE_FIND_ROOT_PATH="/path/to/prefix" ..

This will allow cmake to find other emscripten-compiled libraries that have been make installd into /path/to/prefix.