summaryrefslogtreecommitdiff
path: root/CMakeLists.txt
blob: f99f26b167afa9efd9efbbe97db2fbc1891158f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
cmake_minimum_required(VERSION 3.13)

file (STRINGS "VERSION" MSCP_VERSION)

project(mscp
	VERSION ${MSCP_VERSION}
	LANGUAGES C)


find_package(Git)
if (Git_FOUND)
	# based on https://github.com/nocnokneo/cmake-git-versioning-example
	execute_process(
		COMMAND	${GIT_EXECUTABLE} describe --tags --match "v*"
		OUTPUT_VARIABLE	GIT_DESCRIBE_VERSION
		RESULT_VARIABLE	GIT_DESCRIBE_ERROR_CODE
		OUTPUT_STRIP_TRAILING_WHITESPACE)
	if(NOT GIT_DESCRIBE_ERROR_CODE)
		set(MSCP_BUILD_VERSION ${GIT_DESCRIBE_VERSION})
	endif()
endif()

if (NOT MSCP_BUILD_VERSION)
	message(STATUS "Failed to determine version via Git. Use VERSION file instead.")
	set(MSCP_BUILD_VERSION v${MSCP_VERSION})
endif()


include(GNUInstallDirs)

set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)

if(APPLE)
	list(APPEND CMAKE_PREFIX_PATH /usr/local) # intel mac homebrew prefix
	list(APPEND CMAKE_PREFIX_PATH /opt/homebrew) # arm mac homebrew prefix
endif() # APPLE


option(BUILD_CONAN OFF) # Build mscp with conan
if(BUILD_CONAN)
	message(STATUS "Build mscp with conan")
endif()

option(BUILD_STATIC OFF) # Build mscp with -static LD flag
if (BUILD_STATIC)
	message(STATUS "Build mscp with -static LD option")
	if (NOT BUILD_CONAN)
		message(WARNING
			"BUILD_STATIC strongly recommended with BUILD_CONAN option")
	endif()
endif()



# add libssh static library
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
set(WITH_SERVER OFF)
set(BUILD_SHARED_LIBS OFF)
set(WITH_EXAMPLES OFF)
set(BUILD_STATIC_LIB ON)
if(BUILD_CONAN)
	message(STATUS
		"Disable libssh GSSAPI support because libkrb5 doesn't exist in conan")
	set(WITH_GSSAPI OFF)
endif()
add_subdirectory(libssh EXCLUDE_FROM_ALL)



# setup mscp compile options
list(APPEND MSCP_COMPILE_OPTS -iquote ${CMAKE_CURRENT_BINARY_DIR}/libssh/include)
list(APPEND MSCP_BUILD_INCLUDE_DIRS
	${mscp_SOURCE_DIR}/src
	${CMAKE_CURRENT_BINARY_DIR}/libssh/include)

list(APPEND MSCP_LINK_LIBS ssh-static)
if(BUILD_CONAN)
	find_package(ZLIB REQUIRED)
	find_package(OpenSSL REQUIRED)
	list(APPEND MSCP_LINK_LIBS ZLIB::ZLIB)
	list(APPEND MSCP_LINK_LIBS OpenSSL::Crypto)
endif()


# Symbol check
check_symbol_exists(strlcat string.h HAVE_STRLCAT)

# generate config.h in build dir
configure_file(
	${mscp_SOURCE_DIR}/include/config.h.in
	${CMAKE_CURRENT_BINARY_DIR}/include/config.h)
list(APPEND MSCP_BUILD_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/include)


# libmscp.a
set(LIBMSCP_SRC
	src/mscp.c src/ssh.c src/fileops.c src/path.c src/platform.c src/message.c
	src/openbsd-compat/strlcat.c)
add_library(mscp-static STATIC ${LIBMSCP_SRC})
target_include_directories(mscp-static
	PRIVATE ${MSCP_BUILD_INCLUDE_DIRS} ${mscp_SOURCE_DIR}/include)
target_compile_options(mscp-static PRIVATE ${MSCP_COMPILE_OPTS})
target_link_libraries(mscp-static PRIVATE ${MSCP_LINK_LIBS})
set_target_properties(mscp-static
	PROPERTIES
	OUTPUT_NAME	mscp)

# mscp executable
list(APPEND MSCP_LINK_LIBS m pthread)

add_executable(mscp src/main.c)
target_include_directories(mscp
	PRIVATE ${MSCP_BUILD_INCLUDE_DIRS} ${mscp_SOURCE_DIR}/include)
target_link_libraries(mscp mscp-static ${MSCP_LINK_LIBS})
if (BUILD_STATIC)
	target_link_options(mscp PRIVATE -static)
endif()
target_compile_options(mscp PRIVATE ${MSCP_COMPILE_OPTS})


install(TARGETS mscp RUNTIME DESTINATION bin)


# mscp manpage and document
configure_file(
	${mscp_SOURCE_DIR}/doc/mscp.1.in
	${PROJECT_BINARY_DIR}/mscp.1)

add_custom_target(update-rst
	COMMENT "Update doc/mscp.rst from mscp.1.in"
	WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
	COMMAND
	pandoc -s -f man mscp.1 -t rst -o ${PROJECT_SOURCE_DIR}/doc/mscp.rst)

install(FILES ${PROJECT_BINARY_DIR}/mscp.1
	DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)


# Test
add_test(NAME	pytest
	COMMAND	python3 -m pytest -v
		--mscp-path=${PROJECT_BINARY_DIR}/mscp ${PROJECT_SOURCE_DIR}/test
	WORKING_DIRECTORY	${PROJECT_BINARY_DIR})

enable_testing()




# Custom targets to build and test mscp in docker containers.
# foreach(IN ZIP_LISTS) (cmake >= 3.17) can shorten the following lists.
# However, ubuntu 20.04 has cmake 3.16.3. So this is a roundabout trick.
list(APPEND DIST_NAMES	ubuntu	ubuntu	rocky	rocky	almalinux	alpine)
list(APPEND DIST_VERS	20.04	22.04	8.9	9.3	9.3		3.19)
list(APPEND DIST_PKGS	deb	deb	rpm	rpm	rpm		static)

list(LENGTH DIST_NAMES _DIST_LISTLEN)
math(EXPR DIST_LISTLEN "${_DIST_LISTLEN} - 1")

foreach(x RANGE ${DIST_LISTLEN})
	list(GET DIST_NAMES	${x} DIST_NAME)
	list(GET DIST_VERS	${x} DIST_VER)
	list(GET DIST_PKGS	${x} DIST_PKG)

	set(DOCKER_IMAGE mscp-${DIST_NAME}:${DIST_VER})
	set(DOCKER_INDEX ${DIST_NAME}-${DIST_VER})
	set(PKG_FILE_NAME
		mscp_${DIST_NAME}-${DIST_VER}-${ARCH}.${DIST_PKG})

	add_custom_target(docker-build-${DOCKER_INDEX}
		COMMENT "Build mscp in ${DOCKER_IMAGE} container"
		WORKING_DIRECTORY ${mscp_SOURCE_DIR}
		COMMAND
		docker build -t ${DOCKER_IMAGE} -f Dockerfile/${DOCKER_INDEX}.Dockerfile .)

	add_custom_target(docker-build-${DOCKER_INDEX}-no-cache
		COMMENT "Build mscp in ${DOCKER_IMAGE} container"
		WORKING_DIRECTORY ${mscp_SOURCE_DIR}
		COMMAND
		docker build --no-cache -t ${DOCKER_IMAGE} -f Dockerfile/${DOCKER_INDEX}.Dockerfile .)

	add_custom_target(docker-test-${DOCKER_INDEX}
		COMMENT "Test mscp in ${DOCKER_IMAGE} container"
		WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
		COMMAND
		docker run --init --rm --sysctl net.ipv6.conf.all.disable_ipv6=0
		${DOCKER_IMAGE} /mscp/scripts/test-in-container.sh)

	list(APPEND DOCKER_BUILDS		docker-build-${DOCKER_INDEX})
	list(APPEND DOCKER_BUILDS_NO_CACHE	docker-build-${DOCKER_INDEX}-no-cache)
	list(APPEND DOCKER_TESTS		docker-test-${DOCKER_INDEX})
endforeach()

add_custom_target(docker-build-all		DEPENDS ${DOCKER_BUILDS})
add_custom_target(docker-build-all-no-cache	DEPENDS ${DOCKER_BUILDS_NO_CACHE})
add_custom_target(docker-test-all		DEPENDS ${DOCKER_TESTS})


### debuild-related definitions

set(DEBBUILDCONTAINER mscp-build-deb)
add_custom_target(build-deb
	COMMENT "build mscp deb files inside a container"
	WORKING_DIRECTORY ${mscp_SOURCE_DIR}
	BYPRODUCTS ${CMAKE_BINARY_DIR}/debbuild
	COMMAND
	docker build -t ${DEBBUILDCONTAINER} -f Dockerfile/build-deb.Dockerfile .
	COMMAND
	docker run --rm -v ${CMAKE_BINARY_DIR}:/out ${DEBBUILDCONTAINER}
	cp -r /debbuild /out/)


### rpmbuild-related definitions

# generate files for rpmbuild
configure_file(
	${mscp_SOURCE_DIR}/rpm/mscp.spec.in
	${mscp_SOURCE_DIR}/rpm/mscp.spec
	@ONLY)
configure_file(
	${mscp_SOURCE_DIR}/Dockerfile/build-srpm.Dockerfile.in
	${mscp_SOURCE_DIR}/Dockerfile/build-srpm.Dockerfile
	@ONLY)

# Custom target to build mscp as a src.rpm in docker.
set(RPMBUILDCONTAINER mscp-build-srpm)
set(SRPMFILE mscp-${MSCP_VERSION}-1.el9.src.rpm)
add_custom_target(build-srpm
	COMMENT "Build mscp src.rpm inside a container"
	WORKING_DIRECTORY ${mscp_SOURCE_DIR}
	BYPRODUCTS ${CMAKE_BINARY_DIR}/${SRPMFILE}
	COMMAND
	docker build -t ${RPMBUILDCONTAINER} -f Dockerfile/build-srpm.Dockerfile .
	COMMAND
	docker run --rm -v ${CMAKE_BINARY_DIR}:/out ${RPMBUILDCONTAINER}
	cp /root/rpmbuild/SRPMS/${SRPMFILE} /out/)

### single-binary-build-related definitions

# Custom target to get single binary mscp
set(SINGLEBINARYFILE mscp.linux.${CMAKE_SYSTEM_PROCESSOR}.static)
add_custom_target(build-single-binary
	COMMENT "Build mscp as a single binary in alpine conatiner"
	WORKING_DIRECTORY ${mscp_SOURCE_DIR}
	BYPRODUCTS ${CMAKE_BINARY_DIR}/${SINGLEBINARYFILE}
	DEPENDS docker-build-alpine-3.19
	COMMAND
	docker run --rm -v ${CMAKE_BINARY_DIR}:/out mscp-alpine:3.19
	cp /mscp/build/mscp /out/${SINGLEBINARYFILE})


add_custom_target(build-pkg-all
	DEPENDS build-deb build-srpm build-single-binary)