cmake_minimum_required(VERSION 2.6)
PROJECT(ACNG CXX C)
INCLUDE_DIRECTORIES(. ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR} "include")

SET(FLAGS_ACNG " -pthread -Wall -D_FILE_OFFSET_BITS=64 ")

# minimum prqs
list(APPEND AcngLdList pthread z bz2)

INCLUDE(CheckIncludeFiles)
INCLUDE(CheckCXXSourceCompiles)

#INCLUDE(FindZLIB) # broken, hangs for 10 seconds
# header check should be enough, gzip should be everywhere nowadays
#CHECK_INCLUDE_FILES("gzip.h" HAVE_ZLIB)
FIND_PATH(HAVE_ZLIB zlib.h )
if(NOT HAVE_ZLIB)
   message(FATAL_ERROR "apt-cacher-ng requires gzip library and development files ${HAVE_ZLIB}")
endif(NOT HAVE_ZLIB)

INCLUDE(FindBZip2)
if (BZIP2_FOUND)
   SET(HAVE_LIBBZ2 1)
   MARK_AS_ADVANCED(HAVE_LIBBZ2)
else (BZIP2_FOUND)
   message(FATAL_ERROR "apt-cacher-ng requires bzip2 library and development files")
endif (BZIP2_FOUND)

INCLUDE_DIRECTORIES(${BZIP2_INCLUDE_DIR})

SET(CMAKE_REQUIRED_FLAGS "-Wl,--as-needed")
SET(TESTSRC "int main() {return 0;}")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_WL_AS_NEEDED)
SET(CMAKE_REQUIRED_FLAGS "")

SET(CMAKE_REQUIRED_LIBRARIES lzma)
SET(TESTSRC "
#include <lzma.h>
lzma_stream t; int main(){ return lzma_stream_decoder (&t, 32000000, LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED); }
")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_LZMA)
IF(HAVE_LZMA)
   list(APPEND AcngLdList lzma)
ELSE(HAVE_LZMA)
   MESSAGE("XZ (liblzma) not found or not working, disabling support")
   SET(HAVE_LZMA )
ENDIF(HAVE_LZMA)
SET(CMAKE_REQUIRED_LIBRARIES "")

SET(TESTSRC "
#include <wordexp.h>
int main(int argc, char **argv) { wordexp_t p; return wordexp(*argv, &p, 0); }
")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_WORDEXP)

SET(TESTSRC "
#include <glob.h>
int main(int argc, char **argv) { glob_t p; return glob(*argv, 0, 0, &p); }
")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_GLOB)

SET(TESTSRC "
#define _XOPEN_SOURCE 600
#include <fcntl.h>
int testme(int fd, off_t offset, off_t len, int) { return posix_fadvise(fd, offset, len, POSIX_FADV_SEQUENTIAL); }; int main(int,char**){return testme(0,0,0,0);}
")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_FADVISE)
# Solaris fallback
IF(NOT HAVE_FADVISE)
SET(TESTSRC "
#include <fcntl.h>
int testme(int fd, off_t offset, off_t len, int) { return posix_fadvise(fd, offset, len, POSIX_FADV_SEQUENTIAL); }; int main(int,char**){return testme(0,0,0,0);}
")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_FADVISE)
ENDIF(NOT HAVE_FADVISE)

SET(TESTSRC "
#include <sys/mman.h>
int testme(void *addr, size_t length, int advice) { return posix_madvise(addr, length, advice); } int main(int,char**){return testme(0,0,0);}
")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_MADVISE)

SET(TESTSRC "
#define _GNU_SOURCE
#include <linux/falloc.h>
#include <fcntl.h>
int main() { int fd=1; return fallocate(fd, FALLOC_FL_KEEP_SIZE, 1, 2); }
")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_LINUX_FALLOCATE)

SET(TESTSRC "
#include <sys/sendfile.h>
int main(int argc, char **argv) { off_t yes(3); return (int) sendfile(1, 2, &yes, 4); }
")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_LINUX_SENDFILE)

FIND_LIBRARY(HAVE_SOCKETLIB socket) # separate socket lib looks like Solaris-like environment
if(HAVE_SOCKETLIB)
   link_libraries(socket nsl)
endif(HAVE_SOCKETLIB)

INCLUDE(CheckTypeSize)
CHECK_TYPE_SIZE(int SIZE_INT)
CHECK_TYPE_SIZE(long SIZE_LONG)

INCLUDE(TestBigEndian)
TEST_BIG_ENDIAN(WORDS_BIGENDIAN)

SET(TESTSRC "
#include <memory>
int main() { return NULL != std::shared_ptr<int>(new int(1)); }
")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_MEMORY_SPTR)

SET(TESTSRC "
#include <tr1/memory>
int main() { return NULL != std::tr1::shared_ptr<int>(new int(1)); }
")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_TR1_MEMORY)

set(CMAKE_REQUIRED_INCLUDES . ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR})

SET(TESTSRC "
#include <boost/smart_ptr.hpp>
int main() { return NULL != boost::shared_ptr<int>(new int(1)); }
")
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_BOOST_SMARTPTR)
set(CMAKE_REQUIRED_INCLUDES "")

if(NOT HAVE_BOOST_SMARTPTR)
   if(NOT HAVE_TR1_MEMORY)
      if(NOT HAVE_MEMORY_SPTR)
         message(FATAL_ERROR "Could not find a working smart pointer implementation. Please read documentation and include boost headers.")
      endif(NOT HAVE_MEMORY_SPTR)
   endif(NOT HAVE_TR1_MEMORY)
endif(NOT HAVE_BOOST_SMARTPTR)

######################################
# checks done, save configuration    #
######################################

CONFIGURE_FILE("${CMAKE_SOURCE_DIR}/include/acsyscap.h.in" "${CMAKE_BINARY_DIR}/acsyscap.h")


# I don't need -rdynamic
SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")

FILE(GLOB SRCS "${CMAKE_SOURCE_DIR}/source/*.cc")
ADD_EXECUTABLE(apt-cacher-ng ${SRCS})
list(REMOVE_DUPLICATES AcngLdList)
TARGET_LINK_LIBRARIES(apt-cacher-ng ${AcngLdList})

SET_TARGET_PROPERTIES(apt-cacher-ng PROPERTIES COMPILE_FLAGS ${FLAGS_ACNG})


ADD_EXECUTABLE(in.acng client/client.cc)
SET_TARGET_PROPERTIES(in.acng PROPERTIES COMPILE_FLAGS ${FLAGS_ACNG})

IF(HAVE_WL_AS_NEEDED)
SET_TARGET_PROPERTIES(in.acng apt-cacher-ng PROPERTIES LINK_FLAGS  -Wl,--as-needed)
# funny hack, link with gcc and avoid libstdc++/libm (since no STL parts used
# there). However, it needs to be investigated - the alternative linking makes
# the binary 40kb larger, might include higher relocation costs and bigger
# chunks of unique memory while libstdc++ needs to be loaded anyway for the
# server process.
#TARGET_LINK_LIBRARIES(in.acng supc++)
#SET_TARGET_PROPERTIES(in.acng PROPERTIES LINKER_LANGUAGE C)
ENDIF(HAVE_WL_AS_NEEDED)


############################################
## Attempt to build acngfs where possible ##
############################################

include(FindPkgConfig)
pkg_check_modules(fuse fuse)

set(acngfs_cflags "${FLAGS_ACNG} -DMINIBUILD")
# what a mess... convert sepator back to space
foreach(arg ${fuse_CFLAGS})
   set(acngfs_cflags "${acngfs_cflags} ${arg}")
endforeach(arg ${fuse_CFLAGS})

# double-check and make sure it compiles
SET(TESTSRC "
#define _FILE_OFFSET_BITS 64
#define FUSE_USE_VERSION 26
#include <fuse.h>
int main() { return 0; }
")
SET(CMAKE_REQUIRED_FLAGS ${fuse_CFLAGS})
CHECK_CXX_SOURCE_COMPILES("${TESTSRC}" HAVE_FUSE_26)

if(fuse_FOUND AND HAVE_FUSE_26)
ADD_EXECUTABLE(acngfs fs/httpfs.cc source/lockable.cc source/header.cc source/caddrinfo.cc source/acbuf.cc source/meta.cc source/acfg.cc source/acfg_defaults.cc)

#message("hm, ${acngfs_cflags}")
SET_TARGET_PROPERTIES(acngfs PROPERTIES COMPILE_FLAGS "${acngfs_cflags}" )
TARGET_LINK_LIBRARIES(acngfs ${fuse_LDFLAGS})

IF(HAVE_WL_AS_NEEDED)
SET_TARGET_PROPERTIES(acngfs PROPERTIES LINK_FLAGS  -Wl,--as-needed)
ENDIF(HAVE_WL_AS_NEEDED)


else(fuse_FOUND AND HAVE_FUSE_26)
   message("FUSE not found or incompatible, not building acngfs")
endif(fuse_FOUND AND HAVE_FUSE_26)
