summaryrefslogtreecommitdiff
path: root/CMakeLists.txt
blob: d99e4f9727d2b5c988c7d6fa13ed9a67c4a3c98c (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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
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()

option(USE_PODMAN OFF) # use podman instread of docker
if(USE_PODMAN)
	message(STATUS "Use podman instead of docker")
	set(CE podman) # CE means Container Engine
else()
	set(CE docker)
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(htonll	arpa/inet.h	HAVE_HTONLL)
check_symbol_exists(ntohll	arpa/inet.h	HAVE_NTOHLL)
check_symbol_exists(strlcat	string.h	HAVE_STRLCAT)
if (NOT HAVE_STRLCAT)
	list(APPEND OPENBSD_COMPAT_SRC src/openbsd-compat/strlcat.c)
endif()


# 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/checkpoint.c
	src/platform.c src/print.c src/pool.c src/strerrno.c
	${OPENBSD_COMPAT_SRC})
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_IDS	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_IDS _DIST_LISTLEN)
math(EXPR DIST_LISTLEN "${_DIST_LISTLEN} - 1")

foreach(x RANGE ${DIST_LISTLEN})
	list(GET DIST_IDS	${x} DIST_ID)
	list(GET DIST_VERS	${x} DIST_VER)
	list(GET DIST_PKGS	${x} DIST_PKG)

	set(DOCKER_IMAGE mscp-${DIST_ID}:${DIST_VER})
	set(DOCKER_INDEX ${DIST_ID}-${DIST_VER})
	execute_process(
		COMMAND ${CMAKE_SOURCE_DIR}/scripts/install-build-deps.sh
		--dont-install --platform Linux-${DIST_ID}
		OUTPUT_VARIABLE REQUIREDPKGS
		OUTPUT_STRIP_TRAILING_WHITESPACE)

	add_custom_target(docker-build-${DOCKER_INDEX}
		COMMENT "Build mscp in ${DOCKER_IMAGE} container"
		WORKING_DIRECTORY ${mscp_SOURCE_DIR}
		COMMAND
		${CE} build --build-arg REQUIREDPKGS=${REQUIREDPKGS}
		-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
		${CE} build --build-arg REQUIREDPKGS=${REQUIREDPKGS} --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
		${CE} 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)
execute_process(
	COMMAND ${CMAKE_SOURCE_DIR}/scripts/install-build-deps.sh
	--dont-install --platform Linux-ubuntu
	OUTPUT_VARIABLE REQUIREDPKGS_DEB
	OUTPUT_STRIP_TRAILING_WHITESPACE)

add_custom_target(build-deb
	COMMENT "build mscp deb files inside a container"
	WORKING_DIRECTORY ${mscp_SOURCE_DIR}
	BYPRODUCTS ${CMAKE_BINARY_DIR}/debbuild
	COMMAND
	${CE} build --build-arg REQUIREDPKGS=${REQUIREDPKGS_DEB}
	-t ${DEBBUILDCONTAINER} -f Dockerfile/build-deb.Dockerfile .
	COMMAND
	${CE} 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)
execute_process(
	COMMAND ${CMAKE_SOURCE_DIR}/scripts/install-build-deps.sh
	--dont-install --platform Linux-rocky
	OUTPUT_VARIABLE REQUIREDPKGS_RPM
	OUTPUT_STRIP_TRAILING_WHITESPACE)

add_custom_target(build-srpm
	COMMENT "Build mscp src.rpm inside a container"
	WORKING_DIRECTORY ${mscp_SOURCE_DIR}
	BYPRODUCTS ${CMAKE_BINARY_DIR}/${SRPMFILE}
	COMMAND
	${CE} build --build-arg REQUIREDPKGS=${REQUIREDPKGS_RPM}
	--build-arg MSCP_VERSION=${MSCP_VERSION}
	-t ${RPMBUILDCONTAINER} -f Dockerfile/build-srpm.Dockerfile .
	COMMAND
	${CE} 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
	${CE} 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)