File Coverage

blib/lib/XS/Install/CMake.pm
Criterion Covered Total %
statement 12 68 17.6
branch 0 14 0.0
condition n/a
subroutine 4 11 36.3
pod 0 3 0.0
total 16 96 16.6


line stmt bran cond sub pod time code
1             package
2             XS::Install::CMake;
3 11     11   78 use strict;
  11         23  
  11         369  
4 11     11   78 use warnings;
  11         21  
  11         372  
5 11     11   11783 use Env qw/@PATH/;
  11         36438  
  11         75  
6 11     11   2201 use Cwd 'abs_path';
  11         29  
  11         10749  
7              
8             sub configure {
9 0     0 0   my $result = run(@_);
10 0           return import_cmake_properites($result);
11             }
12              
13             sub run {
14 0     0 0   my ($bdir, $props_dir, $target, $options) = @_;
15 0           $props_dir = abs_path($props_dir); # in case, it has symlink in path: cmake cannot work with build dirs with symlink parts
16 0           my $ok = eval { require Alien::cmake3; 1 };
  0            
  0            
17 0 0         die "This module requires Alien::cmake3 to build.\n" unless $ok;
18              
19 0           unshift @PATH, Alien::cmake3->bin_dir;
20 0 0         open(CMAKELISTS, '>', "$props_dir/CMakeLists.txt") or die $!;
21              
22 0           print CMAKELISTS <<'EOS';
23             cmake_minimum_required(VERSION 3.5)
24             project(GetProps)
25              
26             macro(find_package)
27             set(find_package_ARGS ${ARGV})
28             list(REMOVE_ITEM find_package_ARGS "REQUIRED")
29             list(APPEND find_package_ARGS "QUIET")
30             _find_package(${find_package_ARGS})
31             endmacro()
32              
33             if (WIN32)
34             list(APPEND CMAKE_FIND_LIBRARY_SUFFIXES .dll)
35             endif()
36              
37             function(is_good_lib_item ret name)
38             set(${ret} FALSE PARENT_SCOPE)
39             if(${name} MATCHES "debug|optimized|general|PRIVATE|PUBLIC|INTERFACE" OR ${name} MATCHES "^-.*" OR TARGET ${name})
40             set(${ret} TRUE PARENT_SCOPE)
41             endif()
42             find_library(${name}_is_good ${name})
43             if(${name}_is_good)
44             set(${ret} TRUE PARENT_SCOPE)
45             endif()
46             endfunction()
47              
48              
49             macro(target_link_libraries)
50             set(TARGET_LINK_LIBS_ARGS ${ARGV})
51             list(REMOVE_AT TARGET_LINK_LIBS_ARGS 0)
52              
53             foreach(ARG ${TARGET_LINK_LIBS_ARGS})
54             is_good_lib_item(is_good ${ARG})
55             message(STATUS "checking " ${ARG} " -> " ${is_good})
56             if(${is_good})
57             list(APPEND TARGET_LINK_LIBS_OK ${ARG})
58             endif()
59             endforeach()
60              
61             if (TARGET_LINK_LIBS_OK)
62             message(STATUS "linking:" ${ARGV0} ${TARGET_LINK_LIBS_OK})
63             _target_link_libraries(${ARGV0} ${TARGET_LINK_LIBS_OK})
64             endif()
65             endmacro()
66              
67             macro(add_library)
68             set(args ${ARGV})
69             list(FIND args IMPORTED index)
70             if (index GREATER_EQUAL 0)
71             MATH(EXPR index "${index}+1")
72             list (INSERT args ${index} GLOBAL)
73             endif()
74             message(STATUS "add_library: ${args}")
75             _add_library(${args})
76             endmacro()
77              
78             add_subdirectory(".." "../build")
79              
80             function(get_all_libs_locations ret tgt)
81             set(self_loc "")
82             get_target_property(lret ${tgt} TYPE)
83             if (NOT ${lret} STREQUAL INTERFACE_LIBRARY)
84             get_target_property(lret ${tgt} IMPORTED_LOCATION)
85             message(STATUS "got:" ${lret} "for" ${tgt})
86             if (lret)
87             set(self_loc ${lret})
88             endif()
89             endif()
90             get_target_property(deps ${tgt} INTERFACE_LINK_LIBRARIES)
91             message(STATUS "deps:" ${deps} "for" ${tgt})
92             foreach(lib ${deps})
93             if (TARGET ${lib})
94             get_all_libs_locations(lret ${lib})
95             list(APPEND self_loc ${lret})
96             endif()
97             endforeach()
98             set(${ret} ${self_loc} PARENT_SCOPE)
99             endfunction()
100              
101             function(write_all_libs_inc tgt)
102             get_target_property(deps ${tgt} INTERFACE_LINK_LIBRARIES)
103             message(STATUS "deps inc:" ${deps} "for" ${tgt})
104             foreach(lib ${deps})
105             if (TARGET ${lib})
106             get_target_property(lret ${lib} INTERFACE_INCLUDE_DIRECTORIES)
107             message(STATUS "GOT_INC=" ${lret})
108             write_all_libs_inc(${lib})
109             endif()
110             endforeach()
111             endfunction()
112              
113             foreach(PROP ${REQUESTED_PROPS})
114             get_target_property(GOT_RES ${REQUESTED_TARGET} ${PROP})
115             if (GOT_RES)
116             message(STATUS "GOT_${PROP}=" "${GOT_RES}")
117             else (GOT_RES)
118             message(STATUS "GOT_${PROP}=")
119             endif (GOT_RES)
120             endforeach()
121              
122             get_target_property(libs ${REQUESTED_TARGET} INTERFACE_LINK_LIBRARIES)
123             if(libs)
124             foreach(lib ${libs})
125             if (NOT TARGET ${lib})
126             list(APPEND lib_result ${lib})
127             endif()
128             endforeach()
129             message(STATUS "GOT_FILTERED_LINK_LIBRARIES=" "${lib_result}")
130             endif()
131              
132             foreach(TARG ${CONF_TARGETS})
133             separate_arguments(OPT UNIX_COMMAND ${${TARG}_COMP_OPTIONS})
134             target_compile_options(${TARG} PRIVATE ${OPT})
135             endforeach()
136              
137             get_all_libs_locations(locs ${REQUESTED_TARGET})
138             message(STATUS "GOT_LOCATIONS=" "${locs}")
139              
140             write_all_libs_inc(${REQUESTED_TARGET})
141              
142             EOS
143              
144 0           close(CMAKELISTS);
145              
146 0           my @properties = qw(INTERFACE_COMPILE_DEFINITIONS INTERFACE_COMPILE_OPTIONS INTERFACE_INCLUDE_DIRECTORIES INTERFACE_LINK_DIRECTORIES INTERFACE_LINK_LIBRARIES INTERFACE_LINK_OPTIONS OUTPUT_NAME NAME IMPORT_PREFIX IMPORT_SUFFIX LINK_LIBRARIES LINK_OPTIONS LINK_FLAGS IMPORTED_LOCATION);
147 0           my $prop_list = join ';', @properties;
148              
149              
150 0           return `cd $props_dir && cmake . -G "Unix Makefiles" $options -DREQUESTED_TARGET=$target -DREQUESTED_PROPS="$prop_list"`;
151             }
152              
153             sub import_cmake_properites {
154 0     0 0   my $source = shift;
155 0           my $result = {
156             INSTALL_INCLUDE => _get_prop($source, 'INTERFACE_INCLUDE_DIRECTORIES', 'INSTALL_INTERFACE'),
157             BUILD_INCLUDE => _get_prop($source, 'INTERFACE_INCLUDE_DIRECTORIES', 'BUILD_INTERFACE'),
158             INC => _get_prop($source, 'INC', 'INSTALL_INTERFACE'),
159             };
160              
161 0           my $libs = _get_prop($source, 'FILTERED_LINK_LIBRARIES');
162 0           my $link_opts = _get_prop($source, 'INTERFACE_LINK_OPTIONS');
163 0           my $locations = _get_prop($source, 'LOCATIONS');
164              
165 0 0         push ( @$link_opts, map({($_ =~ /^-/) ? $_ : "-l$_"} @$libs), @$locations );
  0            
166 0           $result->{"LIBS"} = $link_opts;
167              
168 0           $result->{"DEFINE"} = [map {"-D$_"} @{_get_prop($source, 'INTERFACE_COMPILE_DEFINITIONS')}];
  0            
  0            
169 0           $result->{"CCFLAGS"} = _get_prop($source, 'IMPORT_COMPILE_OPTIONS');
170              
171 0           my $ok = eval { require Alien::cmake3; 1 };
  0            
  0            
172 0 0         die "This module requires Alien::cmake3 to build.\n" unless $ok;
173 0           $result->{"CMAKE_BIN"} = File::Spec->catfile(Alien::cmake3->bin_dir, Alien::cmake3->exe);
174              
175 0           return $result;
176             }
177              
178             sub _get_raw_prop {
179 0     0     my ($source, $prop_name) = @_;
180 0           my @result = ($source =~ /(?<=GOT_$prop_name=)(.+?)$/gm);
181 0           return \@result;
182             }
183              
184             sub _split_cmake_generator {
185 0     0     my $str = shift;
186 0           return ;
187             }
188              
189             sub _transform_cmake_generator {
190 0     0     my ($vals, $generator_key) = @_;
191 0           my @result;
192 0           for my $str (@$vals) {
193 0           my @splited = ($str =~ /(?:\$<.*?>)|(?:[^\$;]+)/g);
194 0           for my $val (@splited) {
195 0 0         if ($val =~ /\$<$generator_key:(.*)>/g) {
196 0           push @result, split(/;/, $1);
197 0           next;
198             }
199 0 0         if ($val =~ /\$/g) { #other generate expression
200 0           next;
201             }
202 0           push @result, $val; #pure value without generators
203             }
204             }
205 0           return \@result;
206             }
207              
208             sub _get_prop {
209 0     0     my ($source, $prop_name, $generator_key) = @_;
210 0           my $res = _get_raw_prop($source, $prop_name);
211 0 0         if ($generator_key) {
212 0           return _transform_cmake_generator($res,$generator_key);
213             } else {
214 0           return [map{split(";", $_)} @$res];
  0            
215             }
216             }
217              
218             1;
219