summaryrefslogtreecommitdiff
path: root/CMakeLists.txt
blob: 29674c38302a17ee85d94a3a45d66b557d525825 (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
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
# This usage of CMake requires at least version 2.4 (checks are made to determine what to use when certain versions lack functions)
cmake_minimum_required(VERSION 2.4 FATAL_ERROR)
if(COMMAND cmake_policy)
  cmake_policy(SET CMP0003 NEW)
endif(COMMAND cmake_policy)

# If the Source dir and the Binary dir are the same, we are building in-source, which we will disallow due to Autotools being there (but only on non-Windows)
if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR} AND NOT WIN32)
  message(FATAL_ERROR "You can not use CMake to build Anope from the root of it's source tree! Remove the CMakeCache.txt file from this directory, then create a separate directory (either below this directory or elsewhere), and then re-run CMake from there.")
endif(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR} AND NOT WIN32)

# Detect is we are using CMake 2.6 or better, these versions include functions that require less work than CMake 2.4 does
if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5)
  set(CMAKE26_OR_BETTER TRUE)
  set(CMAKE244_OR_BETTER TRUE)
  set(CMAKE242_OR_BETTER TRUE)
else(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5)
  set(CMAKE26_OR_BETTER FALSE)
  # Also detect if we are using CMake 2.4.4 or better, the CheckCXXCompilerFlag module is non-existant in earlier versions
  if(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} GREATER 2.4.3)
    set(CMAKE244_OR_BETTER TRUE)
    set(CMAKE242_OR_BETTER TRUE)
  else(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} GREATER 2.4.3)
    set(CMAKE244_OR_BETTER FALSE)
    # ALSO detect if we are using CMake 2.4.2 or better, the APPEND sub-command of list() is non-existant in earlier versions
    if(CMAKE_PATCH_VERSION GREATER 1)
      set(CMAKE242_OR_BETTER TRUE)
    else(CMAKE_PATCH_VERSION GREATER 1)
      set(CMAKE242_OR_BETTER FALSE)
    endif(CMAKE_PATCH_VERSION GREATER 1)
  endif(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} GREATER 2.4.3)
endif(${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5)

# If the user specifies -DCMAKE_BUILD_TYPE on the command line, take their definition
# and dump it in the cache along with proper documentation, otherwise set CMAKE_BUILD_TYPE
# to Debug prior to calling PROJECT()
# Only do this if not using Visual Studio
if(NOT MSVC)
  if(CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
  else(CMAKE_BUILD_TYPE)
    set(CMAKE_BUILD_TYPE DEBUG CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
  endif(CMAKE_BUILD_TYPE)
endif(NOT MSVC)

# Set the project as C++ primarily, but have C enabled for the checks required later
project(Anope CXX)
enable_language(C)

# If running under MinGW, we have to force the resource compiler settings (hopefully this will be fixed in a later version of CMake)
if(MINGW)
  set(CMAKE_RC_COMPILER_INIT windres)
  enable_language(RC)
  set(CMAKE_RC_COMPILE_OBJECT "<CMAKE_RC_COMPILER> <FLAGS> <DEFINES> -o <OBJECT> <SOURCE>")
endif(MINGW)

# Include the checking functions used later in this CMakeLists.txt
include(CheckFunctionExists)
include(CheckIncludeFile)
include(CheckTypeSize)
include(CheckLibraryExists)
if(CMAKE244_OR_BETTER)
  include(CheckCXXCompilerFlag)
else(CMAKE244_OR_BETTER)
  include(TestCXXAcceptsFlag)
endif(CMAKE244_OR_BETTER)

# Add an optional variable for using run-cc.pl for building, Perl will be checked later regardless of this setting
option(USE_RUN_CC_PL "Use run-cc.pl for building" OFF)

# Use the following directories as includes
include_directories(${Anope_SOURCE_DIR}/include ${Anope_BINARY_DIR}/include ${Anope_BINARY_DIR}/lang)

# If using Windows, always add the _WIN32 define
if(WIN32)
  add_definitions(-D_WIN32)
endif(WIN32)

# If using Visual Studio, set the C++ flags accordingly
if(MSVC)
  # Remove the default exception handling flags, also remove default warning level flag
  string(REPLACE "/EHsc " "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
  string(REPLACE "/GX " "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
  string(REPLACE "/W3 " "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
  # Set the compile flags to have warnings on the max setting (but disable a few annoying ones), exception handling turned on, the proper defines
  set(CXXFLAGS "${CXXFLAGS} /W4 /wd4251 /wd4706 /wd4800 /wd4996 /EHs")
  add_definitions(-DMSVCPP -D_CRT_SECURE_NO_WARNINGS)
# Otherwise, we're not using Visual Studio
else(MSVC)
  # Set the compile flags to have all warnings on (including shadowed variables)
  set(CXXFLAGS "${CXXFLAGS} -Wall -Wshadow")
  # If on a *nix system, also set the compile flags to remove GNU extensions (favor ISO C++) as well as reject non-ISO C++ code, also remove all leading underscores in exported symbols
  if(UNIX)
    set(CXXFLAGS "${CXXFLAGS} -ansi -pedantic -fno-leading-underscore")
    # Set the module-specific compile flags to the same setting as the compile flags
    set(MODULE_CXXFLAGS "${CXXFLAGS}")
  # If we aren't on a *nix system, we are using MinGW
  else(UNIX)
    # Also, if we are building under MinGW, add another define for MinGW
    if(MINGW)
      add_definitions(-DMINGW)
    endif(MINGW)
  endif(UNIX)
endif(MSVC)

# If CMake has found that the given system requires a special library for dl* calls, include it with the linker flags
if(CMAKE_DL_LIBS)
  set(LDFLAGS "${LDFLAGS} -l${CMAKE_DL_LIBS}")
endif(CMAKE_DL_LIBS)

# Under MinGW, the -shared flag isn't properly set in the module-specific linker flags, add it from the C flags for shared libraries
if(MINGW)
  set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS}")
endif(MINGW)

# Under Windows, we set the executable name for Anope to be anope
if(WIN32)
  set(PROGRAM_NAME anope)
# Under *nix, we set the executable name for Anope to be services
else(WIN32)
  set(PROGRAM_NAME services)
endif(WIN32)

# If we are not using Visual Studio, we'll run the following checks
if(NOT MSVC)
  # Check if the C++ compiler can accept the -pipe flag, and add it to the compile flags if it works
  if(CMAKE244_OR_BETTER)
    # If using CMake 2.4.4 or better, we can use check_cxx_compiler_flag
    check_cxx_compiler_flag(-pipe HAVE_PIPE_FLAG)
  else(CMAKE244_OR_BETTER)
    # If using CMake 2.4.3 or older, we will use check_cxx_accepts_flags instead
    check_cxx_accepts_flag(-pipe HAVE_PIPE_FLAG)
  endif(CMAKE244_OR_BETTER)
  # If the flag was accepted, add it to the list of flags
  if(HAVE_PIPE_FLAG)
    set(CXXFLAGS "${CXXFLAGS} -pipe")
  endif(HAVE_PIPE_FLAG)

  # The following are additional library checks, they are not required for Windows
  if(NOT WIN32)
    # Check if socket is within the socket library (if the library exists), and add it to the linker flags if needed
    check_library_exists(socket socket "" HAVE_SOCKET_LIB)
    if(HAVE_SOCKET_LIB)
      set(LDFLAGS "${LDFLAGS} -lsocket")
    endif(HAVE_SOCKET_LIB)
  endif(NOT WIN32)
endif(NOT MSVC)

# If DEFUMASK wasn't passed to CMake, set a default depending on if RUNGROUP was passed in or not
if(NOT DEFUMASK)
  if(RUNGROUP)
    set(DEFUMASK "007")
  else(RUNGROUP)
    set(DEFUMASK "077")
  endif(RUNGROUP)
endif(NOT DEFUMASK)

# Check for the existance of the following include files
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
check_include_file(strings.h HAVE_STRINGS_H)
check_include_file(sys/select.h HAVE_SYS_SELECT_H)

# Check for the existance of the following functions
check_function_exists(gethostbyname HAVE_GETHOSTBYNAME)
check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
check_function_exists(setgrent HAVE_SETGRENT)
check_function_exists(strcasecmp HAVE_STRCASECMP)
check_function_exists(stricmp HAVE_STRICMP)
check_function_exists(strlcat HAVE_STRLCAT)
check_function_exists(strlcpy HAVE_STRLCPY)
check_function_exists(umask HAVE_UMASK)
check_function_exists(backtrace HAVE_BACKTRACE)

# Check for the existance of the following types
check_type_size(uint8_t UINT8_T)
check_type_size(u_int8_t U_INT8_T)
check_type_size(int16_t INT16_T)
check_type_size(uint16_t UINT16_T)
check_type_size(u_int16_t U_INT16_T)
check_type_size(int32_t INT32_T)
check_type_size(uint32_t UINT32_T)
check_type_size(u_int32_t U_INT32_T)

# Only CMake 2.6.x and later contain the STRIP sub-command for string()
if(CMAKE26_OR_BETTER)
  # Strip the leading and trailing spaces from the compile flags
  if(CXXFLAGS)
    string(STRIP ${CXXFLAGS} CXXFLAGS)
  endif(CXXFLAGS)
  # Strip the leading and trailing spaces from the linker flags
  if(LDFLAGS)
    string(STRIP ${LDFLAGS} LDFLAGS)
  endif(LDFLAGS)
endif(CMAKE26_OR_BETTER)

# A macro to handle appending to lists
macro(append_to_list LIST)
  if(CMAKE242_OR_BETTER)
    # For CMake 2.4.2 or better, we can just use the APPEND sub-command of list()
    list(APPEND ${LIST} ${ARGN})
  else(CMAKE242_OR_BETTER)
    # For CMake 2.4.x before 2.4.2, we have to do this manually use set() instead
    set(${LIST} ${${LIST}} ${ARGN})
  endif(CMAKE242_OR_BETTER)
endmacro(append_to_list)

# A macro to handle reading specific lines from a file
macro(read_from_file FILE REGEX STRINGS)
  if(CMAKE26_OR_BETTER)
    # For CMake 2.6.x or better, we can just use this function to get the lines that match the given regular expression
    file(STRINGS ${FILE} RESULT REGEX ${REGEX})
  else(CMAKE26_OR_BETTER)
    # For CMake 2.4.x, we need to do this manually, firsly we read the file in
    file(READ ${FILE} ALL_STRINGS)
    # Next we replace all newlines with semicolons
    string(REGEX REPLACE "\n" ";" ALL_STRINGS ${ALL_STRINGS})
    # Clear the result list
    set(RESULT)
    # Iterate through all the lines of the file
    foreach(STRING ${ALL_STRINGS})
      # Check for a match against the given regular expression
      string(REGEX MATCH ${REGEX} STRING_MATCH ${STRING})
      # If we had a match, append the match to the list
      if(STRING_MATCH)
        append_to_list(RESULT ${STRING})
      endif(STRING_MATCH)
    endforeach(STRING)
  endif(CMAKE26_OR_BETTER)
  # Set the given STRINGS variable to the result
  set(${STRINGS} ${RESULT})
endmacro(read_from_file)

# A macro to handle searching within a list
macro(find_in_list LIST ITEM_TO_FIND FOUND)
  if(CMAKE26_OR_BETTER OR ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} GREATER 2.4.7)
    # For CMake 2.6.x or better (as well as CMake 2.4.8 or better), we can use the FIND sub-command of list()
    list(FIND ${LIST} ${ITEM_TO_FIND} ITEM_FOUND)
  else(CMAKE26_OR_BETTER OR ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} GREATER 2.4.7)
    # For CMake 2.4.x before 2.4.8, we have to do this ourselves (NOTE: This is very slow due to a lack of break() as well), firstly we set that we a temporary boolean
    set(ITEM_FOUND -1)
    set(POS 0)
    # Iterate through the list
    foreach(ITEM ${${LIST}})
      # If the item we are looking at is the item we are trying to find, set that we've found the item
      if(${ITEM} STREQUAL ${ITEM_TO_FIND})
        set(ITEM_FOUND ${POS})
      endif(${ITEM} STREQUAL ${ITEM_TO_FIND})
      math(EXPR POS "${POS} + 1")
    endforeach(ITEM)
  endif(CMAKE26_OR_BETTER OR ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION} GREATER 2.4.7)
  # Set the given FOUND variable to the result
  set(${FOUND} ${ITEM_FOUND})
endmacro(find_in_list)

# A macro to handle removing duplicates from a list
macro(remove_list_duplicates LIST)
  if(CMAKE26_OR_BETTER)
    # For CMake 2.6.x or better, this can be done automatically
    list(REMOVE_DUPLICATES ${LIST})
  else(CMAKE26_OR_BETTER)
    # For CMake 2.4.x, we have to do this ourselves, firstly we'll clear a temporary list
    set(NEW_LIST)
    # Iterate through the old list
    foreach(ITEM ${${LIST}})
      # Check if the item is in the new list
      find_in_list(NEW_LIST ${ITEM} FOUND_ITEM)
      if(FOUND_ITEM EQUAL -1)
        # If the item was not found, append it to the list
        append_to_list(NEW_LIST ${ITEM})
      endif(FOUND_ITEM EQUAL -1)
    endforeach(ITEM)
    # replace the old list with the new list
    set(${LIST} ${NEW_LIST})
  endif(CMAKE26_OR_BETTER)
endmacro(remove_list_duplicates)

# Search for the following programs
find_program(GREP grep)
find_program(SH sh)
find_program(CHGRP chgrp)
find_program(CHMOD chmod)
find_program(PERL perl)

# If perl is included on the system and the user wants to use run-cc.pl, change the commands for compiling and linking
if(PERL AND USE_RUN_CC_PL)
  set(CMAKE_CXX_COMPILE_OBJECT "${PERL} ${Anope_SOURCE_DIR}/run-cc.pl -q ${CMAKE_CXX_COMPILE_OBJECT}")
  set(CMAKE_CXX_LINK_EXECUTABLE "${PERL} ${Anope_SOURCE_DIR}/run-cc.pl -q ${CMAKE_CXX_LINK_EXECUTABLE}")
  set(CMAKE_CXX_CREATE_SHARED_MODULE "${PERL} ${Anope_SOURCE_DIR}/run-cc.pl -q ${CMAKE_CXX_CREATE_SHARED_MODULE}")
endif(PERL AND USE_RUN_CC_PL)

# If a INSTDIR was passed in to CMake, use it as the install prefix, otherwise set the default install prefix to the services directory under the user's home directory
if(INSTDIR)
  set(CMAKE_INSTALL_PREFIX "${INSTDIR}")
else(INSTDIR)
  set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/services")
endif(INSTDIR)

# Version number processing
# Find all lines in version.log that start with VERSION_
read_from_file(${Anope_SOURCE_DIR}/version.log "^VERSION_" VERSIONS)
# Iterate through the strings found
foreach(VERSION_STR ${VERSIONS})
  # Get the length of the string
  string(LENGTH ${VERSION_STR} VERSION_LEN)
  # Subtract 16 from the string's length (8 for VERSION_, 5 more for the type, 2 for the space and leading quote, 1 for the trailing quote)
  math(EXPR VERSION_NUM_LEN "${VERSION_LEN} - 16")
  # Extract the type from the string
  string(SUBSTRING ${VERSION_STR} 8 5 VERSION_TYPE)
  # Extract the actual value from the string
  string(SUBSTRING ${VERSION_STR} 15 ${VERSION_NUM_LEN} VERSION)
  # Set the version type to the value extract from above
  set(VERSION_${VERSION_TYPE} ${VERSION})
endforeach(VERSION_STR ${VERSIONS})

# Set the version variables based on what was found above
set(VERSION_COMMA "${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_BUILD}")
set(VERSION_DOTTED_NOBUILD "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}")
set(VERSION_DOTTED "${VERSION_DOTTED_NOBUILD}.${VERSION_BUILD}")
set(VERSION_FULL "${VERSION_DOTTED}${VERSION_EXTRA}")
set(VERSION_FULL_NOBUILD "${VERSION_DOTTED_NOBUILD}${VERSION_EXTRA}")

# Only do the following for Windows
if(WIN32)
  # Generate the win32.rc file using the above variables
  configure_file(${Anope_SOURCE_DIR}/src/win32.rc.cmake ${Anope_BINARY_DIR}/src/win32.rc)
endif(WIN32)

# Calculate dependencies for each header
# I would've done this inside the CMakeLists.txt for the include directory, but since it's added AFTER everything else, it won't help...

# Firstly, find all the header files
file(GLOB_RECURSE ALL_HEADERS "*.h")
# Iterate through the headers
foreach(HEADER ${ALL_HEADERS})
  # Don't process the file if it's in an obsolete directory
  if(NOT HEADER MATCHES ".*obsolete.*")
    append_to_list(TMP_HEADERS ${HEADER})
    # In addition, also set up a variable to store the fullpath of the header, in a variable prefixed with just the header's filename for easy access later
    get_filename_component(HEADER_FILENAME ${HEADER} NAME)
    set(${HEADER_FILENAME}_FULLPATH ${HEADER})
  endif(NOT HEADER MATCHES ".*obsolete.*")
endforeach(HEADER)
# Set the list of headers to be all the non-obsolete ones, then sort the list
set(ALL_HEADERS ${TMP_HEADERS})
if(CMAKE244_OR_BETTER)
  list(SORT ALL_HEADERS)
endif(CMAKE244_OR_BETTER)

# This function will take a #include line and extract the filename minus the quotes
macro(extract_include_filename INCLUDE FILENAME)
  # Detect if there is any trailing whitespace (basically see if the last character is a space or a tab)
  string(LENGTH ${INCLUDE} INCLUDE_LEN)
  math(EXPR LAST_CHAR_POS "${INCLUDE_LEN} - 1")
  string(SUBSTRING ${INCLUDE} ${LAST_CHAR_POS} 1 LAST_CHAR)
  # Only strip if the last character was a space or a tab
  if(LAST_CHAR STREQUAL " " OR LAST_CHAR STREQUAL "\t")
    # Strip away trailing whitespace from the line
    string(REGEX REPLACE "[ \t]*$" "" INCLUDE_STRIPPED ${INCLUDE})
  else(LAST_CHAR STREQUAL " " OR LAST_CHAR STREQUAL "\t")
    # Just copy INCLUDE to INCLUDE_STRIPPED so the below code doesn't complain about a lack of INCLUDE_STRIPPED
    set(INCLUDE_STRIPPED ${INCLUDE})
  endif(LAST_CHAR STREQUAL " " OR LAST_CHAR STREQUAL "\t")
  # Find the filename including the quotes, it should be at the end of the line after whitespace was stripped
  string(REGEX MATCH "\".*\"$" FILE ${INCLUDE_STRIPPED})
  # Get the length of the filename with quotes
  string(LENGTH ${FILE} FILENAME_LEN)
  # Subtract 2 from this length, for the quotes
  math(EXPR FILENAME_LEN "${FILENAME_LEN} - 2")
  # Overwrite the filename with a version sans quotes
  string(SUBSTRING ${FILE} 1 ${FILENAME_LEN} FILE)
  # Set the filename to the the given variable
  set(${FILENAME} "${FILE}")
endmacro(extract_include_filename)

# Preparse step 1: get filenames sans paths
# Iterate through the headers
foreach(HEADER ${ALL_HEADERS})
  # Find all the lines in the current header that have any form of #include on them, regardless of whitespace
  read_from_file(${HEADER} "^[ \t]*#[ \t]*include[ \t]*\".*\"[ \t]*$" INCLUDES)
  # Get the filename only of the header we just checked
  get_filename_component(HEADER_FILENAME ${HEADER} NAME)
  # Iterate through the strings containing #include (if any)
  foreach(INCLUDE ${INCLUDES})
    # Extract the filename from the #include line
    extract_include_filename(${INCLUDE} FILENAME)
    # Append this filename to the list of headers for the header we are checking
    append_to_list(${HEADER_FILENAME}_HEADERS ${FILENAME})
  endforeach(INCLUDE)
endforeach(HEADER)

# Preparse step 2: for every header from above that had includes, recursively find the headers each header relies on
# Iterate through the headers (again)
foreach(HEADER ${ALL_HEADERS})
  # Get the filename only of the current header
  get_filename_component(HEADER_FILENAME ${HEADER} NAME)
  # If there were any include, we'll be checking them
  if(${HEADER_FILENAME}_HEADERS)
    # Set the variables, old for all previously found headers, new for all newly found headers
    set(OLD_HEADERS)
    set(HEADERS ${${HEADER_FILENAME}_HEADERS})
    set(NEW_HEADERS)
    # Loop as long as there are still headers to be parsed
    while(HEADERS)
      # Iterate through the list of the current headers
      foreach(CURR_HEADER ${HEADERS})
        # If that header has headers it relies on, we'll add them to the list of new headers
        if(${CURR_HEADER}_HEADERS)
          foreach(CURR_HEADERS_HEADER ${${CURR_HEADER}_HEADERS})
            append_to_list(NEW_HEADERS ${CURR_HEADERS_HEADER})
          endforeach(CURR_HEADERS_HEADER)
        endif(${CURR_HEADER}_HEADERS)
      endforeach(CURR_HEADER)
      # Append the headers we checked to the old headers
      append_to_list(OLD_HEADERS ${HEADERS})
      # Set the headers to check to the new headers (it may be empty and that'll exit the loop)
      set(HEADERS ${NEW_HEADERS})
      # Erase the new headers
      set(NEW_HEADERS)
    endwhile(HEADERS)
    # OLD_HEADERS will now contain all headers that the current header relies on, remove duplicate headers from the list and sort the list
    remove_list_duplicates(OLD_HEADERS)
    if(CMAKE244_OR_BETTER)
      list(SORT OLD_HEADERS)
    endif(CMAKE244_OR_BETTER)
    # Set the current header's list of headers to the cleaned up list from above
    set(${HEADER_FILENAME}_HEADERS ${OLD_HEADERS})
  endif(${HEADER_FILENAME}_HEADERS)
endforeach(HEADER)

# The following headers are generated from CMake rules and won't be found with the above
append_to_list(ALL_HEADERS ${Anope_BINARY_DIR}/lang/language.h ${Anope_BINARY_DIR}/include/sysconf.h ${Anope_BINARY_DIR}/include/version.h)
set(language.h_FULLPATH ${Anope_BINARY_DIR}/lang/language.h)
set(sysconf.h_FULLPATH ${Anope_BINARY_DIR}/include/sysconf.h)
set(version.h_FULLPATH ${Anope_BINARY_DIR}/include/version.h)

# This function is used in most of the src (sub)directories to calculate the header file dependencies for the given source file
macro(calculate_depends SRC)
  # Find all the lines in the given source file that have any form of #include on them, regardless of whitespace
  read_from_file(${SRC} "^[ \t]*#[ \t]*include[ \t]*\".*\"[ \t]*$" INCLUDES)
  # Reset the list of headers to empty
  set(HEADERS)
  # Iterate through the strings containing #include (if any)
  foreach(INCLUDE ${INCLUDES})
    # Extract the filename from the #include line
    extract_include_filename(${INCLUDE} FILENAME)
    # Append the filename to the list of headers
    append_to_list(HEADERS ${FILENAME})
  endforeach(INCLUDE)
  # Set the list of new headers to empty (this will store all the headers that the above list depends on)
  set(NEW_HEADERS)
  # Iterate through the list of headers
  foreach(HEADER ${HEADERS})
    # If the current header has it's own headers to depend on, append those to the list of new headers
    if(${HEADER}_HEADERS)
      append_to_list(NEW_HEADERS ${${HEADER}_HEADERS})
    endif(${HEADER}_HEADERS)
  endforeach(HEADER)
  # If there were new headers, append them to the list of headers
  if(NEW_HEADERS)
    append_to_list(HEADERS ${NEW_HEADERS})
  endif(NEW_HEADERS)
  # If after all the above there is a list of header, we'll process them, converting them to full paths
  if(HEADERS)
    # Remove duplicate headers from the list and sort the list
    remove_list_duplicates(HEADERS)
    if(CMAKE244_OR_BETTER)
      list(SORT HEADERS)
    endif(CMAKE244_OR_BETTER)
    # Set the list of full path headers to empty
    set(HEADERS_FULL)
    # Iterate through the list of headers
    foreach(HEADER ${HEADERS})
      # Append the full path of the header to the full path headers list
      append_to_list(HEADERS_FULL ${${HEADER}_FULLPATH})
    endforeach(HEADER)
    # Set the given source file to depend on the headers given
    set_source_files_properties(${SRC} PROPERTIES OBJECT_DEPENDS "${HEADERS_FULL}")
  endif(HEADERS)
endmacro(calculate_depends)

# A macro to update the environment variable CPACK_IGNORED_FILES which contains a list of files for CPack to ignore
macro(add_to_cpack_ignored_files ITEM)
  # Temporary copy of the orignal item
  set(REAL_ITEM "${ITEM}")
  # If we have 2+ arguments, assume that the second one was something like TRUE (doesn't matter really) and convert periods so they will be \\. for CPack
  if(${ARGC} GREATER 1)
    string(REPLACE "." "\\\\." REAL_ITEM ${REAL_ITEM})
  endif(${ARGC} GREATER 1)
  # If the environment variable is already defined, just tack the item to the end
  if(DEFINED ENV{CPACK_IGNORED_FILES})
    set(ENV{CPACK_IGNORED_FILES} "$ENV{CPACK_IGNORED_FILES};${REAL_ITEM}")
  # Otherwise set the environment variable to the item
  else(DEFINED ENV{CPACK_IGNORED_FILES})
    set(ENV{CPACK_IGNORED_FILES} "${REAL_ITEM}")
  endif(DEFINED ENV{CPACK_IGNORED_FILES})
endmacro(add_to_cpack_ignored_files)

# Add the initial files to ignore which will be ignored regardless of if you are building in-source or out-of-source
add_to_cpack_ignored_files(".git\;config.cache\;.svn\;CMakeFiles\;sysconf.h$\;Makefile.inc$\;config.log\;config.status" TRUE)
# Add the files we don't want the periods converted for
add_to_cpack_ignored_files(".\\\\\\\\.so$;.\\\\\\\\.o$;.\\\\\\\\.s$;${Anope_SOURCE_DIR}/Makefile$")
# If the two directories are the same, we are building in-source, thus we need to ignore more files from the build
if(${Anope_SOURCE_DIR} STREQUAL ${Anope_BINARY_DIR})
  # Add the files that need their periods converted
  add_to_cpack_ignored_files("Makefile\;cmake_install.cmake\;sysconf.h$\;CMakeCache.txt\;install_manifest.txt" TRUE)
  # Add the files we don't want the periods converted for
  add_to_cpack_ignored_files(".\\\\\\\\.so$;CPack.;anope-${VERSION_FULL_NOBUILD}-source\\\\\\\\..")
  # If using Visual Studio, add these files as well
  if(MSVC)
    add_to_cpack_ignored_files(".vcproj$\;.sln$\;.ncb$\;.suo$\;.dir$\;.ilk$\;.exp$\;.pdb$\;.lib$\;/debug$;/release$;/relwithdebinfo$;/minsizerel$" TRUE)
  endif(MSVC)
endif(${Anope_SOURCE_DIR} STREQUAL ${Anope_BINARY_DIR})

# Go into the following directories and run their CMakeLists.txt as well
add_subdirectory(data)
add_subdirectory(docs)
add_subdirectory(lang)
add_subdirectory(src)
add_subdirectory(include)

# Get the filename of the Anope binary, to use later
get_target_property(SERVICES_BINARY ${PROGRAM_NAME} LOCATION)
get_filename_component(SERVICES_BINARY ${SERVICES_BINARY} NAME)

# At install time, create the following additional directories
install(CODE "file(MAKE_DIRECTORY \"\${CMAKE_INSTALL_PREFIX}/data/backups\")")
install(CODE "file(MAKE_DIRECTORY \"\${CMAKE_INSTALL_PREFIX}/data/logs\")")
install(CODE "file(MAKE_DIRECTORY \"\${CMAKE_INSTALL_PREFIX}/data/modules/runtime\")")
# On non-Windows platforms, if RUNGROUP is set, change the permissions of the below directories, as well as the group of the data directory
if(NOT WIN32 AND RUNGROUP)
  install(CODE "execute_process(COMMAND ${CHMOD} 2775 \"\${CMAKE_INSTALL_PREFIX}/data/backups\")")
  install(CODE "execute_process(COMMAND ${CHMOD} 2775 \"\${CMAKE_INSTALL_PREFIX}/data/logs\")")
  install(CODE "execute_process(COMMAND ${CHMOD} 2775 \"\${CMAKE_INSTALL_PREFIX}/data/modules/runtime\")")
  install(CODE "execute_process(COMMAND ${CHGRP} -R ${RUNGROUP} \"\${CMAKE_INSTALL_PREFIX}\")")
endif(NOT WIN32 AND RUNGROUP)
# On Windows platforms, install extra files
if(WIN32)
  install(FILES ${Anope_SOURCE_DIR}/anope.bat
    DESTINATION bin
  )
  install(FILES ${Anope_SOURCE_DIR}/Changes ${Anope_SOURCE_DIR}/Changes.conf ${Anope_SOURCE_DIR}/Changes.lang
    DESTINATION .
  )
endif(WIN32)

# Only process the CPack section if we have CPack
if(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")
  # Override the module include path to include our directory, as we are using our own version of the NSIS template
  set(CMAKE_MODULE_PATH ${Anope_SOURCE_DIR})
  # Various options for CPack
  set(CPACK_PACKAGE_NAME "Anope IRC Services")
  set(CPACK_PACKAGE_VENDOR "Anope Team")
  set(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR})
  set(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR})
  set(CPACK_PACKAGE_VERSION_PATCH "${VERSION_PATCH}${VERSION_EXTRA}")
  set(CPACK_PACKAGE_FILE_NAME "anope-${VERSION_FULL_NOBUILD}")
  set(CPACK_RESOURCE_FILE_LICENSE "${Anope_SOURCE_DIR}/docs/COPYING")
  # The following doesn't actually do anything. :(
  #set(CPACK_RESOURCE_FILE_README "${Anope_SOURCE_DIR}/docs/README")
  # The following is primarily for NSIS
  if(WIN32)
    # Also for Windows, include installing the MSVCRT library
    include(InstallRequiredSystemLibraries)
    set(CPACK_GENERATOR "NSIS")
    set(CPACK_PACKAGE_INSTALL_DIRECTORY "Anope")
    set(CPACK_PACKAGE_EXECUTABLES "")
    set(CPACK_NSIS_MENU_LINKS
      "bin\\\\${SERVICES_BINARY}" "Anope IRC Services"
      "bin\\\\anope.bat\\\" \\\"-debug -nofork" "Anope IRC Services (Debug and Window Logging)"
      "bin\\\\anope.bat\\\" \\\"-nofork" "Anope IRC Services (Window Logging)"
      "bin\\\\anope.bat\\\" \\\"-nothird" "Anope IRC Services (No Third Party Modules)"
      "http://www.anope.org" "Anope Web Site"
    )
    # The following doesn't work, but a bug report has been filed about it
    #set(CPACK_CREATE_DESKTOP_LINK_${SERVICES_BINARY} TRUE)
    set(CPACK_NSIS_MUI_ICON "${Anope_SOURCE_DIR}/src\\\\anope-icon.ico")
    set(CPACK_NSIS_MUI_UNIICON "${Anope_SOURCE_DIR}/src\\\\anope-icon.ico")
    set(CPACK_NSIS_INSTALLED_ICON_NAME "${SERVICES_BINARY}")
    set(CPACK_NSIS_URL_INFO_ABOUT "http://www.anope.org")
    set(CPACK_NSIS_COMPRESSOR "/SOLID lzma")
  endif(WIN32)
  set(CPACK_SOURCE_PACKAGE_FILE_NAME "anope-${VERSION_FULL_NOBUILD}-source")
  set(CPACK_SOURCE_IGNORE_FILES "$ENV{CPACK_IGNORED_FILES}")
  set(CPACK_MONOLITHIC_INSTALL TRUE)
  include(CPack)
endif(EXISTS "${CMAKE_ROOT}/Modules/CPack.cmake")