1#
2# SPDX-License-Identifier: BSD-3-Clause
3#
4# Copyright © 2022 Keith Packard
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9#
10# 1. Redistributions of source code must retain the above copyright
11#    notice, this list of conditions and the following disclaimer.
12#
13# 2. Redistributions in binary form must reproduce the above
14#    copyright notice, this list of conditions and the following
15#    disclaimer in the documentation and/or other materials provided
16#    with the distribution.
17#
18# 3. Neither the name of the copyright holder nor the names of its
19#    contributors may be used to endorse or promote products derived
20#    from this software without specific prior written permission.
21#
22# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33# OF THE POSSIBILITY OF SUCH DAMAGE.
34#
35
36# Add sources to libc, eliding any duplicate basenames
37function(picolibc_sources_flags flags)
38
39  # Get current sources
40  get_property(current_sources_real TARGET c PROPERTY SOURCES)
41  get_property(current_sources_fake TARGET c PROPERTY SOURCES_FAKE)
42  set(current_sources ${current_sources_real} ${current_sources_fake})
43  set(sources ${ARGN})
44
45  foreach(source IN LISTS ARGN)
46    # Compare desired addition to existing sources using basenames
47    get_filename_component(source_base "${source}" NAME_WLE)
48    foreach(current IN LISTS current_sources)
49      get_filename_component(current_base "${current}" NAME_WLE)
50      if("${source_base}" STREQUAL "${current_base}")
51	list(REMOVE_ITEM sources "${source}")
52      endif()
53    endforeach()
54  endforeach()
55
56  # Add all files that aren't duplicated
57  target_sources(c PRIVATE ${sources})
58
59  # Set flags if specified
60  if(flags)
61    foreach(flag ${flags})
62      foreach(source ${sources})
63	set_property(SOURCE ${source}
64	  TARGET_DIRECTORY c
65	  APPEND PROPERTY COMPILE_OPTIONS ${flag})
66      endforeach()
67    endforeach()
68  endif()
69endfunction()
70
71function(picolibc_sources)
72  picolibc_sources_flags(0 ${ARGN})
73endfunction()
74
75function(picolibc_sources_fake)
76  get_property(current_sources_fake TARGET c PROPERTY SOURCES_FAKE)
77  list(APPEND current_sources_fake ${ARGN})
78  set_property(TARGET c PROPERTY SOURCES_FAKE ${current_sources_fake})
79endfunction()
80
81function(picolibc_headers subdir)
82
83  # Get current headers
84  get_property(current_headers GLOBAL PROPERTY PICOLIBC_HEADERS)
85
86  set(orig_headers ${ARGN})
87
88  foreach(header IN LISTS ARGN)
89    set(rel_header "${subdir}/${header}")
90    set(include 1)
91    foreach(current IN LISTS current_headers)
92      if("${rel_header}" STREQUAL "${current}")
93	list(REMOVE_ITEM orig_headers "${header}")
94	set(include 0)
95      endif()
96    endforeach()
97    if(include)
98      list(APPEND current_headers "${rel_header}")
99      configure_file("${header}" "${PROJECT_BINARY_DIR}/picolibc/include/${rel_header}")
100    endif()
101  endforeach()
102  set_property(GLOBAL PROPERTY PICOLIBC_HEADERS ${current_headers})
103  install(FILES ${orig_headers} DESTINATION "include/${subdir}")
104endfunction()
105
106function(_picolibc_supported_compile_options var)
107  set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
108  foreach(flag ${ARGN})
109    string(MAKE_C_IDENTIFIER ${flag} flag_under)
110    try_compile(${flag_under} "${PROJECT_BINARY_DIR}"
111      "${CMAKE_CURRENT_SOURCE_DIR}/cmake/simple-main.c"
112      COMPILE_DEFINITIONS "${PICOLIBC_TEST_COMPILE_OPTIONS};${PICOLIBC_FLAG_OPTIONS};${flag}"
113      )
114    if(${${flag_under}})
115      list(APPEND options ${flag})
116    endif()
117  endforeach()
118  set(${var} ${options} PARENT_SCOPE)
119endfunction()
120
121# These flags are needed to generate errors for invalid command line flags
122# instead of just warnings
123_picolibc_supported_compile_options(PICOLIBC_FLAG_OPTIONS
124  -Werror=missing-declarations
125  -Werror=unknown-attributes
126  -Werror=attributes
127  -Werror=unsupported-floating-point-opt
128  -Werror=ignored-optimization-argument
129  -Wno-unused-command-line-argument
130  )
131
132function(picolibc_supported_compile_options)
133  _picolibc_supported_compile_options(options ${ARGN})
134  set(PICOLIBC_COMPILE_OPTIONS ${PICOLIBC_COMPILE_OPTIONS} ${options} PARENT_SCOPE)
135endfunction()
136
137function(picolibc_flag flag)
138
139  string(REPLACE "_" "-" flag_dash ${flag})
140  string(REGEX REPLACE "^-" "" flag_trim ${flag_dash})
141  string(TOLOWER ${flag_trim} flag_lower)
142  set(flag_file "${CMAKE_CURRENT_SOURCE_DIR}/cmake/${flag_lower}.c")
143
144  if (NOT EXISTS "${flag_file}")
145    message(ERROR " Missing compiler test file ${flag_file}")
146  endif()
147
148  set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
149
150  try_compile(${flag} "${PROJECT_BINARY_DIR}" "${flag_file}"
151    COMPILE_DEFINITIONS "${PICOLIBC_FLAG_OPTIONS}"
152    )
153
154  if (${flag})
155    set(${flag} ${flag} PARENT_SCOPE)
156  endif()
157endfunction()
158
159